ArrayDeque 分析

197 阅读2分钟

循环数组(circular array) ,ArrayDeque 是非线程安全的,当多个线程同时使用的时候,需要手动同步;而且,该容器不允许放入null元素。

用于表示 栈和队列

1 底层数据结构

对象数组,head指向第一个有效元素 ,tail指向第一个可以插入的空位。

transient Object[] elements; // non-private to simplify nested class access

transient int head;

transient int tail;

2 构造方法

  • ArrayDeque() 初始化大小为 16 的数组
  • ArrayDeque(int numElements) 初始化数组,大小为 大于等于 numElements 的 2 的指数倍 的最小值,最小为 8 .
  • ArrayDeque(Collection<? extends E> c) 初始化数组,大小为 大于等于 c.size() 的 2 的指数倍的最小值,最小为 8, 然后添加 c 中元素。
public ArrayDeque() {
    elements = 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) {
    elements = new Object[calculateSize(numElements)];
}


private void allocateElements(int numElements) {
    elements = new Object[calculateSize(numElements)];
}

// 
private static int calculateSize(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
    }
    return initialCapacity;
}

3 添加方法

  • addFirst(E e) 在首端插入元素,即在head的前面插入元素,空间不够则 调用 doubleCapacity 方法扩容 2 倍。

这里 head = (head - 1) & (elements.length - 1) ,由于 elements.length 是 2 的指数倍, elements.length - 1 的地位全是 1 . 此时进行 & 运算,相当于对其取模。

public void addFirst(E e) {
    if (e == null)
        throw new NullPointerException();
    elements[head = (head - 1) & (elements.length - 1)] = e;
    if (head == tail)
        doubleCapacity();
}
  • addLast(E e) 在尾端插入元素,即在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();
}

4 删除方法

  • removeFirst()
  • removeLast()

5 删除并返回

  • pollFirst()
  • pollLast()

6 获取方法

  • getFirst() 非null,是null值报错。
  • getLast() null报错。
  • peekFirst() 也是获取head元素,可以为 null,表示空数组。
  • peekLast() 也是获取尾元素tail-1,可以为 null,表示空数组。

7 删除指定对象

  • removeFirstOccurrence(Object o)
  • removeLastOccurrence(Object o)