JDK之ArrayDeque源码解析
2017-02-06 16:41
302 查看
刚入java不久的程序猿,对于简单的使用已毫不满足,最终为了一探究竟,翻开了JDK的源码,以下观点为自己的理解及看了多篇博客的总结,欢迎各位大神指出不对的地方,当然也欢迎和我一样刚学的同学,一起加油努力吧~~
ArrayDeque是什么?deque英文翻译为双向队列,ArrayDeque就是实现了Deque接口的一个双向队列的集合,ArrayDeque也是由数组实现,数组的任意位置都可以作为头或者尾,ArrayDeque不允许元素为null
在上面我们了解到了ArrayDeque是什么,大致在脑海中留下初步的印象,接下来我们来看一下源码,由于Deque继承了Queue接口,这里我们就先来看下这个接口里定义的方法
这里的方法已经注释过,大家可以自己看下每个方法的作用,还有就是Queue是继承了Collection接口的,说明最终扔是以迭代的方式来完成的,好了,我们在大致看下Deque接口定义的方法
上面就是Deque接口里的方法,看起来方法很多,其实方法无非就是添加,删除,取值,只不过添加删除头部还是尾部以及返回值的不同而已,整个体系看完,接着看最主要的,ArrayDque的源码
上面就是ArrayDeque的继承与实现,接下来看一下定义的变量
这里队列的头与尾,可以说数组中任意位置都可以为头或者尾,继续看代码
上面是ArrayDeque的构造方法,感觉没什么特殊的东西,就是初始化数组,只不过一个是默认的16长度,一个是传入的参数,最后一个构造在初始化数组后,调用AbstractCollection的addAll方法将集合放入,继续看几个比较重要的方法
好了,这里列出了ArrayDeque最主要的一些方法,其他方法大多都比较简单了,大家可以自己去翻一下源码,最后我们需要注意的是ArrayDeque存元素时,不能存入null元素,否则会报空指针异常,好了,ArrayDeque的解析到这里就结束了
ArrayDeque是什么 |
ArrayDeque源码解析 |
public interface Queue<E> extends Collection<E> { /** * 插入元素,成功返回true,失败抛出异常 */ boolean add(E e); /** * 插入元素,成功返回true,失败返回false */ boolean offer(E e); /** * 获取并删除队首元素,队列为空则抛出异常 */ E remove(); /** * 获取并删除队首元素,队列为空是返回null */ E poll(); /** * 获取但不删除队首元素,队列为空抛出异常 */ E element(); /** * 获取但不删除队首元素,队列为空返回null */ E peek(); }
这里的方法已经注释过,大家可以自己看下每个方法的作用,还有就是Queue是继承了Collection接口的,说明最终扔是以迭代的方式来完成的,好了,我们在大致看下Deque接口定义的方法
public interface Deque<E> extends Queue<E> { /** * 在队列最前端插入元素,无返回值 */ void addFirst(E e); /** * 在队列最后端插入元素,无返回值 */ void addLast(E e); /** * 在队列最前端插入元素,成功返回true失败返回false */ boolean offerFirst(E e); /** * 在队列最后端插入元素,成功返回true失败返回false */ boolean offerLast(E e); /** * 获取并删除队列最前端元素,队列为空抛出异常 */ E removeFirst(); /** * 获取并删除队列最后端元素,队列为空抛出异常 */ E removeLast(); /** * 获取并删除队列最前端元素,队列为空返回null */ E pollFirst(); /** * 获取并删除队列最后端元素,队列为空返回null */ E pollLast(); /** * 获取但不删除队列最前端元素,队列为空抛出异常 */ E getFirst(); /** * 获取但不删除队列最后端元素,队列为空抛出异常 */ E getLast(); /** * 获取但不删除队列最前端元素,队列为空返回null */ E peekFirst(); /** * 获取但不删除队列最后端元素,队列为空返回null */ E peekLast(); /** * 删除队列里第一次出现的指定元素 */ boolean removeFirstOccurrence(Object o); /** * 删除队列里最后一次出现的指定元素 */ boolean removeLastOccurrence(Object o); // *** Queue methods *** boolean add(E e); boolean offer(E e); E remove(); E poll(); E element(); E peek(); // *** Stack methods *** /** * 内存空间允许的情况下,将元素放入出现在栈中的Dqueue中 * 成功返回true,失败抛出异常 */ void push(E e); /** * 删除并返回这个队列的第一个元素 */ E pop(); // *** Collection methods *** /** * 删除某个元素 */ boolean remove(Object o); /** * 是否包含某个元素 */ boolean contains(Object o); /** * 元素数量 */ public int size(); /** * 迭代 */ Iterator<E> iterator(); /** * 返回一个顺序反转后的迭代器 */ Iterator<E> descendingIterator(); }
上面就是Deque接口里的方法,看起来方法很多,其实方法无非就是添加,删除,取值,只不过添加删除头部还是尾部以及返回值的不同而已,整个体系看完,接着看最主要的,ArrayDque的源码
public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, Cloneable, Serializable{ ... }
上面就是ArrayDeque的继承与实现,接下来看一下定义的变量
/** * 存取队列元素的数组 */ private transient E[] elements; /** * 队列的头 */ private transient int head; /** * 队列的尾 */ private transient int tail; /** * 创建新的队列时最小容量 */ private static final int MIN_INITIAL_CAPACITY = 8;
这里队列的头与尾,可以说数组中任意位置都可以为头或者尾,继续看代码
/** * 无参构造,初始化大小为默认大小16 */ public ArrayDeque() { elements = (E[]) new Object[16]; } /** * 有参构造,参数为元素数量 */ public ArrayDeque(int numElements) { allocateElements(numElements); } /** * 有参构造,参数为集合 */ public ArrayDeque(Collection<? extends E> c) { allocateElements(c.size()); addAll(c); } /** * 初始化数组 */ private void allocateElements(int numElements) { //初始化数组的最小容量 int initialCapacity = MIN_INITIAL_CAPACITY; //找到大于numElements的最小的2的幂整数 if (numElements >= initialCapacity) { initialCapacity = numElements; initialCapacity |= (initialCapacity >>> 1); initialCapacity |= (initialCapacity >>> 2); initialCapacity |= (initialCapacity >>> 4); initialCapacity |= (initialCapacity >>> 8); initialCapacity |= (initialCapacity >>> 16); initialCapacity++; if (initialCapacity < 0) // Too many elements, must back off initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements } //参数小于最小容量时,初始化大小为最小容量 elements = (E[]) new Object[initialCapacity]; }
上面是ArrayDeque的构造方法,感觉没什么特殊的东西,就是初始化数组,只不过一个是默认的16长度,一个是传入的参数,最后一个构造在初始化数组后,调用AbstractCollection的addAll方法将集合放入,继续看几个比较重要的方法
/** * 扩容方法,当数组满了进行扩容操作,大小为原来的两倍 */ private void doubleCapacity() { assert head == tail; int p = head; //元素个数 int n = elements.length; int r = n - p; // number of elements to the right of p //将容量扩大一倍 int newCapacity = n << 1; if (newCapacity < 0) throw new IllegalStateException("Sorry, deque too big"); Object[] a = new Object[newCapacity]; //数组分为两段复制 System.arraycopy(elements, p, a, 0, r); System.arraycopy(elements, 0, a, r, p); elements = (E[])a; head = 0; tail = n; } /** * 在队列的前端添加元素,无返回值 */ public void addFirst(E e) { if (e == null) throw new NullPointerException(); elements[head = (head - 1) & (elements.length - 1)] = e; //判断头尾是否重合,重合即数组满了,需进行扩容 if (head == tail) doubleCapacity(); } /** * 在队列的后端添加元素,无返回值 */ public void addLast(E e) { if (e == null) throw new NullPointerException(); elements[tail] = e; //判断头尾是否重合,重合即数组满了,需进行扩容 if ( (tail = (tail + 1) & (elements.length - 1)) == head) doubleCapacity(); } /** * 在队列的前端添加元素,调用addFirst方法,返回值true */ public boolean offerFirst(E e) { addFirst(e); return true; } /** * 在队列的后端添加元素,调用addLast方法,返回值true */ public boolean offerLast(E e) { addLast(e); return true; } /** * 获取并删除最前端元素 */ public E removeFirst() { E x = pollFirst(); //为空时抛出异常 if (x == null) throw new NoSuchElementException(); return x; } /** * 获取并删除最后端元素 */ public E removeLast() { E x = pollLast(); //为空时抛出异常 if (x == null) throw new NoSuchElementException(); return x; } public E pollFirst() { int h = head; //队列空为则元素为空 E result = elements[h]; if (result == null) return null; //head处置空 elements[h] = null; //处理特殊情况,当h为elements.length-1时的情况 head = (h + 1) & (elements.length - 1); return result; } public E pollLast() { //处理特殊情况,当tail为0时的情况 int t = (tail - 1) & (elements.length - 1); E result = elements[t]; if (result == null) return null; elements[t] = null; //下一个需要添加的下标 tail = t; return result; } /** * 获取但不删除队列最前端元素 */ public E getFirst() { E x = elements[head]; //队列为空抛出异常 if (x == null) throw new NoSuchElementException(); return x; } /** * 获取但不删除队列最后端元素 */ public E getLast() { E x = elements[(tail - 1) & (elements.length - 1)]; //队列为空抛出异常 if (x == null) throw new NoSuchElementException(); return x; } /** * 获取但不删除队列最前端元素,队列为空返回null */ public E peekFirst() { return elements[head]; } /** * 获取但不删除队列最后端元素,队列为空返回null */ public E peekLast() { return elements[(tail - 1) & (elements.length - 1)]; }
好了,这里列出了ArrayDeque最主要的一些方法,其他方法大多都比较简单了,大家可以自己去翻一下源码,最后我们需要注意的是ArrayDeque存元素时,不能存入null元素,否则会报空指针异常,好了,ArrayDeque的解析到这里就结束了
相关文章推荐
- 给jdk写注释系列之jdk1.6容器(11)-Queue之ArrayDeque源码解析
- JDK 源码解析 —— ArrayBlockingQueue
- Jdk1.6 JUC源码解析(12)-ArrayBlockingQueue
- 【JDK】:CopyOnWriteArrayList、CopyOnWriteArraySet 源码解析
- java.util.ArrayDeque源码解析
- 基于jdk动态代理的实现与源码解析
- jquery源码解析:proxy,access,swap,isArraylike详解
- java ArrayList 源码解析(jdk1.6)
- JDK源码阅读之Queue接口和Deque接口
- 【jdk源码解析二】java.uti.HashMap源码解析
- 内存优化之ArrayMap源码解析
- JDK 1.7 Integer.parseInt 源码解析
- JDK源码解析之ArrayList
- JDK 源码解析 —— AtomicInteger
- jdk的动态代理源码解析
- JDk Set及HashSet源码解析
- 通过JDK源码解析Thread(Runable target ...)调用的是哪个run方法
- java动态代理Proxy源码解析(Jdk 1.6)
- 【jdk源码解析一】java.util.Observer与java.util.Observable
- 观V8源码中的array.js,解析 Array.prototype.slice为什么能将类数组对象转为真正的数组?