<span style="font-size:18px;">ArrayDeque继承了集合的抽象类AbstractCollection<E> ,实现了 Deque<E>, Cloneable, Serializable三个接口。</span>
从名字可以看出该队列是由循环数组实现的。
<span style="font-size:18px;"> 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 = (E[]) new Object[initialCapacity];
}</span>
这段代码实现了分配一个合适的2的N次幂的容量的数组。>>>表示无符号右移,最高位补零(>>表示有符号右移,正数补零,负数补1)。右移一位相当于除以2,因为int 占据4哥字节,32位,最高位符号位,所以最大表示2^31-1。
<span style="font-size:18px;"> initialCapacity |= (initialCapacity >>> 1);
initialCapacity |= (initialCapacity >>> 2);
initialCapacity |= (initialCapacity >>> 4);
initialCapacity |= (initialCapacity >>> 8);
initialCapacity |= (initialCapacity >>> 16);</span>
这一段代码相当于把initialCapacity的最高位(非零)开始所有位都置为1 ,比如:100011011111到111111111111。当 initialCapacity大于2^30时,会返回2^31是负数,所以要进行判断。
当队列容量不够就进行扩展,乘以2
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 addLast(E e) {
if (e == null)
throw new NullPointerException();
elements[tail] = e;
if ( <span style="color:#FF0000;">(tail = (tail + 1) & (elements.length - 1))</span> == head)
doubleCapacity();
}