概况
ArrayDeque是Deque的主要实现类,Deque的定义为double ended queue,即双端队列,可以从头或尾部插入和删除数据。LinkedList使用的是双链表实现的。ArrayDeque使用环形数组来实现。下面通过分析源码来了解是如何实现的。
构造函数
//无参构造,设置默认大小为16
public ArrayDeque() {
elements = new Object[16];
}
//传入容器大小,如果小于最小值,使用最小值;如果不是2的n次幂,变成最接近的2的n次幂的值
public ArrayDeque(int numElements) {
allocateElements(numElements);
}
// 传入集合,创建容器,并全部添加
public ArrayDeque(Collection<? extends E> c) {
allocateElements(c.size());
addAll(c);
}
//该方法用于初始化容器,核心还是容器大小的值是如何选择的
private void allocateElements(int numElements) {
elements = new Object[calculateSize(numElements)];
}
//计算合适的size
size必须是2的n次幂,如果不是就要找到最接近的值。 理论上最接近的值是最高位再进一位是1其他都是0的时候 例如 127二进制是0111 1111,最接近的2的n次幂是 1000 0000 。
发现 最高位后面全是1的时候的值为 2^n-1。int类型的最大为32位,因此就出现了下面无符号右移的5次的计算方式。
最后再加1 就可以获取到2的n次幂了
private static final int MIN_INITIAL_CAPACITY = 8;
private static int calculateSize(int numElements) {
int initialCapacity = MIN_INITIAL_CAPACITY;
if (numElements >= initialCapacity) {
initialCapacity = numElements;
initialCapacity |= (initialCapacity >>> 1);
initialCapacity |= (initialCapacity >>> 2);
initialCapacity |= (initialCapacity >>> 4);
initialCapacity |= (initialCapacity >>> 8);
initialCapacity |= (initialCapacity >>> 16);
initialCapacity++;
//防止溢出导致符号位变成1导致值为负
if (initialCapacity < 0) // Too many elements, must back off
initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
}
return initialCapacity;
}
ADD方法
初始状态是head和tail是一个位置
从头添加时 head-1 并且与 length-1取模获取位置,然后添加
从尾添加时 先添加,再将tail+1
当添加数据后head==tail时进行2倍扩容
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();
}