ArrayDeque和LinkedList同样都实现了双端队列Deque接口,但它们内部的数据结构和使用方法却不同。根据该类的源码注释翻译可知:html
public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, Cloneable, Serializable
因此ArrayDeque既能够做为队列(包括双端队列xxxFirst,xxxLast),也能够做为栈(pop/push/peek)使用,并且它的效率也是很是高,下面就让咱们一块儿来读一读jdk1.8的源码。java
//存储队列元素的数组 //power of two transient Object[] elements; //队列头部元素的索引 transient int head; //添加一个元素的索引 transient int tail; //最小的初始化容量(指定大小构造器使用) private static final int MIN_INITIAL_CAPACITY = 8;
//默认16个长度 public ArrayDeque() { elements = new Object[16]; } public ArrayDeque(int numElements) { allocateElements(numElements); } public ArrayDeque(Collection<? extends E> c) { allocateElements(c.size()); addAll(c); }
ArrayDeque经过allocateElements()方法进行扩容。下面是allocateElements()源码:算法
private void allocateElements(int numElements) { int initialCapacity = MIN_INITIAL_CAPACITY; // Find the best power of two to hold elements. // Tests "<=" because arrays aren't kept full. 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 = new Object[initialCapacity]; }
ArrayDeque<Integer> arrayDeque = new ArrayDeque<>(8);
下面就从主要函数中来找找答案。数组
扩容是调用doubleCapacity() 方法,当head和tail值相等时,会进行扩容,扩容大小翻倍。安全
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 = a; head = 0; tail = n; }
经过位与计算找到下一个元素的位置。数据结构
public boolean add(E e) { addLast(e); return true; }
public void addLast(E e) { if (e == null) throw new NullPointerException(); elements[tail] = e; if ( (tail = (tail + 1) & (elements.length - 1)) == head) doubleCapacity(); }
add()函数实际上调用了addLast()函数,顾名思义这是将元素添加到队列尾。前提是不能添加空元素。函数
8 & 7 = 0 (1000 & 111)
这就是为了上面说的位与计算elements.length - 1 以此获得下一个元素的位置tail。性能
和addLast相反,添加的元素都在队列最前面线程
public void addFirst(E e) { if (e == null) throw new NullPointerException(); elements[head = (head - 1) & (elements.length - 1)] = e; if (head == tail) doubleCapacity(); }
-1 & (lements.length - 1)= lements.length - 1
因此第一次添加一个元素后head就变为lements.length - 1翻译
例如:
ArrayDeque<Integer> arrayDeque = new ArrayDeque<>(7); arrayDeque.addFirst(1); arrayDeque.addFirst(2); arrayDeque.addFirst(3);
执行时,ArrayDeque内部数组结构变化为:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
3 | 2 | 1 |
第一次添加前head为0,添加时计算:head = -1 & 7 , 计算head获得7。
public E remove() { return removeFirst(); } public E removeFirst() { E x = pollFirst(); if (x == null) throw new NoSuchElementException(); return x; }
public E pollFirst() { int h = head; @SuppressWarnings("unchecked") E result = (E) elements[h]; // Element is null if deque empty if (result == null) return null; elements[h] = null; // Must null out slot head = (h + 1) & (elements.length - 1); return result; }
删除元素其实是调用pollFirst()函数。
head = (h + 1) & (elements.length - 1); 位与计算head移动到下一个位置
public int size() { return (tail - head) & (elements.length - 1); }