ArrayDeque源码解析

187 阅读2分钟

概况

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();
}