ArrayDeque源码分析

简介

ArrayDeque为双端队列,支持首部,尾部两端的操作,因此做双端操作可用于FIFO等queue, 做单端操作可做为stack(先进后出). 运用数组实现队列,

一、Deque接口

二、ArrayDeque 数据结构实现

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
public class ArrayDeque<E> extends AbstractCollection<E>
                           implements Deque<E>, Cloneable, Serializable
{
    /**
     * The array in which the elements of the deque are stored.
     * The capacity of the deque is the length of this array, which is
     * always a power of two. The array is never allowed to become
     * full, except transiently within an addX method where it is
     * resized (see doubleCapacity) immediately upon becoming full,
     * thus avoiding head and tail wrapping around to equal each
     * other.  We also guarantee that all array cells not holding
     * deque elements are always null.
     * 存储了双端队列元素的数组。该deque的容量是这个数组的长度,这总是2的幂。该数组永远不会被允许变满,
     * 除非暂时在addX方法中被调整大小(请参阅双倍容量),因此避免头部和尾部相互缠绕。我们还保证所有不包含deque元素的
     * 数组单元始终为空。
     * 
     * 数组作为存储结构
     */
    private transient E[] elements;

    /**
     * The index of the element at the head of the deque (which is the
     * element that would be removed by remove() or pop()); or an
     * arbitrary number equal to tail if the deque is empty.
     * 
     * deque头部元素的索引(这是remove()或pop()将被移除的元素);或者如果双端队列是空的,则任意数字等于尾部。
     */
    private transient int head;

    /**
     * The index at which the next element would be added to the tail
     * of the deque (via addLast(E), add(E), or push(E)).
     * 
     * 下一个元素将添加到deque尾部的索引(通过添加Last(E),add(E)或push(E))。
     */
    private transient int tail;

    /**
     * The minimum capacity that we'll use for a newly created deque.
     * Must be a power of 2.
     * 我们将为新创建的deque使用的最小容量。必须是2的幂。
     */
    private static final int MIN_INITIAL_CAPACITY = 8;

    // ******  Array allocation and resizing utilities ******

    /**
     * Allocate empty array to hold the given number of elements.
     * 分配空数组以保存给定的元素数目。
     * @param numElements  the number of elements to hold
     */
    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 祝你好运分配2 ^ 30元素
        }
        elements = (E[]) new Object[initialCapacity];
    }

    /**
     * Double the capacity of this deque.  Call only when full, i.e.,
     * when head and tail have wrapped around to become equal.
     * 双倍扩容双队列
     */
    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;  // 往右移1位,扩容2倍
        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;
    }

    /**
     * Copies the elements from our element array into the specified array,
     * in order (from first to last element in the deque).  It is assumed
     * that the array is large enough to hold all elements in the deque.
     *  复制元素 调用toArray
     * @return its argument
     */
    private <T> T[] copyElements(T[] a) {
        if (head < tail) {
            System.arraycopy(elements, head, a, 0, size());
        } else if (head > tail) {
            int headPortionLen = elements.length - head;
            System.arraycopy(elements, head, a, 0, headPortionLen);
            System.arraycopy(elements, 0, a, headPortionLen, tail);
        }
        return a;
    }

    /**
     * Constructs an empty array deque with an initial capacity
     * sufficient to hold 16 elements.
     */
    public ArrayDeque() {
        elements = (E[]) new Object[16];
    }

    /**
     * Constructs an empty array deque with an initial capacity
     * sufficient to hold the specified number of elements.
     *
     * @param numElements  lower bound on initial capacity of the deque
     */
    public ArrayDeque(int numElements) {
        allocateElements(numElements);
    }

    /**
     * Constructs a deque containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.  (The first element returned by the collection's
     * iterator becomes the first element, or <i>front</i> of the
     * deque.)
     *
     * @param c the collection whose elements are to be placed into the deque
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayDeque(Collection<? extends E> c) {
        allocateElements(c.size());
        addAll(c);
    }
}    

有意思代码,主要作用就是最高1位后面都补成1.类似于Integer.highestOneBit方法。 比如: initialCapacity=17 二进制 0000 0000 0000 0000 0000 0000 0001 0001

  • (1).initialCapacity |= (initialCapacity »> 1); 0000 0000 0000 0000 0000 0000 0001 0001 0000 0000 0000 0000 0000 0000 0000 1000 | 0000 0000 0000 0000 0000 0000 0001 1001
  • (2).initialCapacity |= (initialCapacity »> 2); 0000 0000 0000 0000 0000 0000 0001 1001 0000 0000 0000 0000 0000 0000 0000 0110 | 0000 0000 0000 0000 0000 0000 0001 1111 第二步已经获取想要值 第三步,第四步,第五步只是出来大数字。
  • (3).initialCapacity |= (initialCapacity »> 4);
  • (4).initialCapacity |= (initialCapacity »> 8);
  • (5).initialCapacity |= (initialCapacity »> 16);
1
2
3
4
5
              initialCapacity |= (initialCapacity >>>  1);
              initialCapacity |= (initialCapacity >>>  2);
              initialCapacity |= (initialCapacity >>>  4);
              initialCapacity |= (initialCapacity >>>  8);
              initialCapacity |= (initialCapacity >>> 16);

三、添加元素

1.addFirst 添加队列头部

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    /**
     * Inserts the specified element at the front of this deque.
     *
     * @param e the element to add
     * @throws NullPointerException if the specified element is null
     */
    public void addFirst(E e) {
        if (e == null)
            throw new NullPointerException();
        elements[head = (head - 1) & (elements.length - 1)] = e;
        if (head == tail) //相等 扩容
            doubleCapacity();
    }


(head - 1) & (elements.length - 1)查找数组下标值,可以取模方式获取,队列大小是以2次方,可以用&获取下标,为性能方法&比取模性能好。

2.addLast 添加队列尾部

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
      /**
       * Inserts the specified element at the end of this deque.
       *
       * <p>This method is equivalent to {@link #add}.
       *
       * @param e the element to add
       * @throws NullPointerException if the specified element is null
       */
      public void addLast(E e) {
          if (e == null)
              throw new NullPointerException();
          elements[tail] = e;
          if ( (tail = (tail + 1) & (elements.length - 1)) == head)
              doubleCapacity();
      }

3.offerFirst 添加队列头部

调用 addFirst方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    /**
     * Inserts the specified element at the front of this deque.
     *
     * @param e the element to add
     * @return <tt>true</tt> (as specified by {@link Deque#offerFirst})
     * @throws NullPointerException if the specified element is null
     */
    public boolean offerFirst(E e) {
        addFirst(e);
        return true;
    }

4.offerLast 添加队列尾部

调用 addLast方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
   /**
     * Inserts the specified element at the end of this deque.
     *
     * @param e the element to add
     * @return <tt>true</tt> (as specified by {@link Deque#offerLast})
     * @throws NullPointerException if the specified element is null
     */
    public boolean offerLast(E e) {
        addLast(e);
        return true;
    }

四、获取元素

1.pollFirst 获取头部元素,并且删除该元素

1
2
3
4
5
6
7
8
9
    public E pollFirst() {
        int h = head;
        E result = elements[h]; // Element is null if deque empty 如果deque是空的,元素是null
        if (result == null)
            return null;
        elements[h] = null;     // Must null out slot 必须空出位置 删除该元素
        head = (h + 1) & (elements.length - 1); //重新获取头下标
        return result;
    }

2.pollLast 获取尾部部元素,并且删除该元素

1
2
3
4
5
6
7
8
9
  public E pollLast() {
        int t = (tail - 1) & (elements.length - 1);  //获取尾部下标
        E result = elements[t];
        if (result == null)
            return null;
        elements[t] = null;  // 必须空出位置 删除该元素
        tail = t;
        return result;
    }

3.getFirst 获取头部元素,并且不删除该元素,为空throw NoSuchElementException

1
2
3
4
5
6
7
8
9
   /**
     * @throws NoSuchElementException {@inheritDoc}
     */
    public E getFirst() {
        E x = elements[head];
        if (x == null)
            throw new NoSuchElementException();
        return x;
    }

4.getLast 获取尾部元素,并且不删除该元素,为空throw NoSuchElementException

1
2
3
4
5
6
7
8
9
    /**
     * @throws NoSuchElementException {@inheritDoc}
     */
    public E getLast() {
        E x = elements[(tail - 1) & (elements.length - 1)];
        if (x == null)
            throw new NoSuchElementException();
        return x;
    }

5.peekFirst 获取头部元素,并且不删除该元素

1
2
3
    public E peekFirst() {
        return elements[head]; // elements[head] is null if deque empty
    }

6.peekFirst 获取尾部部元素,并且不删除该元素

1
2
3
    public E peekLast() {
        return elements[(tail - 1) & (elements.length - 1)];
    }

五、删除元素

1.removeFirst 删除该元素,为空throw NoSuchElementException

调用pollFirst方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

 /**
  * @throws NoSuchElementException {@inheritDoc}
  */
 public E removeFirst() {
     E x = pollFirst();
     if (x == null)
         throw new NoSuchElementException();
     return x;
 }

2.removeLast 删除该元素,为空throw NoSuchElementException

调用pollLast方法

1
2
3
4
5
6
7
8
9
    /**
     * @throws NoSuchElementException {@inheritDoc}
     */
    public E removeLast() {
        E x = pollLast();
        if (x == null)
            throw new NoSuchElementException();
        return x;
    }

3.delete 删除指定下标值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    /**
     * Removes the element at the specified position in the elements array,
     * adjusting head and tail as necessary.  This can result in motion of
     * elements backwards or forwards in the array.
     * 在元素数组中删除指定位置的元素,必要时调整头和尾。这可能导致数组中的元素向后或向后移动。
     * <p>This method is called delete rather than remove to emphasize
     * that its semantics differ from those of {@link List#remove(int)}.
     *
     * @return true if elements moved backwards
     */
    private boolean delete(int i) {
        checkInvariants();
        final E[] elements = this.elements;
        final int mask = elements.length - 1;
        final int h = head;
        final int t = tail;
        final int front = (i - h) & mask;//删除前面数量
        final int back  = (t - i) & mask;//删除后面数量

        // Invariant: head <= i < tail mod circularity
        if (front >= ((t - h) & mask))
            throw new ConcurrentModificationException();

        // Optimize for least element motion 优化最小元素运动 判断删除下标前后数量做判断 是否往前移动 还是往后移动
        if (front < back) {
            if (h <= i) { 
                System.arraycopy(elements, h, elements, h + 1, front); // 往头结点后移动1位
            } else { // Wrap around
                System.arraycopy(elements, 0, elements, 1, i);         //
                elements[0] = elements[mask];
                System.arraycopy(elements, h, elements, h + 1, mask - h);  
            }
            elements[h] = null;
            head = (h + 1) & mask;
            return false;
        } else {
            if (i < t) { // Copy the null tail as well
                System.arraycopy(elements, i + 1, elements, i, back);   //往尾结点前移动1位
                tail = t - 1;
            } else { // Wrap around
                System.arraycopy(elements, i + 1, elements, i, mask - i);
                elements[mask] = elements[0];
                System.arraycopy(elements, 1, elements, 0, t);
                tail = (t - 1) & mask;
            }
            return true;
        }
    }

head<tai且head<i<tail,

head>tail且i<tail,

head>tail且tail<i<head,

4.removeFirstOccurrence 往头查询,删除指定元素

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

  /**
   * Removes the first occurrence of the specified element in this
   * deque (when traversing the deque from head to tail).
   * If the deque does not contain the element, it is unchanged.
   * More formally, removes the first element <tt>e</tt> such that
   * <tt>o.equals(e)</tt> (if such an element exists).
   * Returns <tt>true</tt> if this deque contained the specified element
   * (or equivalently, if this deque changed as a result of the call).
   *
   * @param o element to be removed from this deque, if present
   * @return <tt>true</tt> if the deque contained the specified element
   */
  public boolean removeFirstOccurrence(Object o) {
      if (o == null)
          return false;
      int mask = elements.length - 1;
      int i = head;
      E x;
      while ( (x = elements[i]) != null) {
          if (o.equals(x)) {
              delete(i);
              return true;
          }
          i = (i + 1) & mask;
      }
      return false;
  }

5.removeLastOccurrence 往尾查询,删除指定元素

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 /**
     * Removes the last occurrence of the specified element in this
     * deque (when traversing the deque from head to tail).
     * If the deque does not contain the element, it is unchanged.
     * More formally, removes the last element <tt>e</tt> such that
     * <tt>o.equals(e)</tt> (if such an element exists).
     * Returns <tt>true</tt> if this deque contained the specified element
     * (or equivalently, if this deque changed as a result of the call).
     *
     * @param o element to be removed from this deque, if present
     * @return <tt>true</tt> if the deque contained the specified element
     */
    public boolean removeLastOccurrence(Object o) {
        if (o == null)
            return false;
        int mask = elements.length - 1;
        int i = (tail - 1) & mask;
        E x;
        while ( (x = elements[i]) != null) {
            if (o.equals(x)) {
                delete(i);
                return true;
            }
            i = (i - 1) & mask;
        }
        return false;
    }

6.clear 清空

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
    /**
     * Removes all of the elements from this deque.
     * The deque will be empty after this call returns.
     */
    public void clear() {
        int h = head;
        int t = tail;
        if (h != t) { // clear all cells
            head = tail = 0;
            int i = h;
            int mask = elements.length - 1;
            do {
                elements[i] = null;
                i = (i + 1) & mask;
            } while (i != t);
        }
    }

六、Queue methods

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
   /**
     * Inserts the specified element at the end of this deque.
     *
     * <p>This method is equivalent to {@link #addLast}.
     *
     * @param e the element to add
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     * @throws NullPointerException if the specified element is null
     */
    public boolean add(E e) {
        addLast(e);
        return true;
    }

    /**
     * Inserts the specified element at the end of this deque.
     *
     * <p>This method is equivalent to {@link #offerLast}.
     *
     * @param e the element to add
     * @return <tt>true</tt> (as specified by {@link Queue#offer})
     * @throws NullPointerException if the specified element is null
     */
    public boolean offer(E e) {
        return offerLast(e);
    }

    /**
     * Retrieves and removes the head of the queue represented by this deque.
     *
     * This method differs from {@link #poll poll} only in that it throws an
     * exception if this deque is empty.
     *
     * <p>This method is equivalent to {@link #removeFirst}.
     *
     * @return the head of the queue represented by this deque
     * @throws NoSuchElementException {@inheritDoc}
     */
    public E remove() {
        return removeFirst();
    }

    /**
     * Retrieves and removes the head of the queue represented by this deque
     * (in other words, the first element of this deque), or returns
     * <tt>null</tt> if this deque is empty.
     *
     * <p>This method is equivalent to {@link #pollFirst}.
     *
     * @return the head of the queue represented by this deque, or
     *         <tt>null</tt> if this deque is empty
     */
    public E poll() {
        return pollFirst();
    }

    /**
     * Retrieves, but does not remove, the head of the queue represented by
     * this deque.  This method differs from {@link #peek peek} only in
     * that it throws an exception if this deque is empty.
     *
     * <p>This method is equivalent to {@link #getFirst}.
     *
     * @return the head of the queue represented by this deque
     * @throws NoSuchElementException {@inheritDoc}
     */
    public E element() {
        return getFirst();
    }

    /**
     * Retrieves, but does not remove, the head of the queue represented by
     * this deque, or returns <tt>null</tt> if this deque is empty.
     *
     * <p>This method is equivalent to {@link #peekFirst}.
     *
     * @return the head of the queue represented by this deque, or
     *         <tt>null</tt> if this deque is empty
     */
    public E peek() {
        return peekFirst();
    }

七、 Stack methods

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
   /**
     * Pushes an element onto the stack represented by this deque.  In other
     * words, inserts the element at the front of this deque.
     *
     * <p>This method is equivalent to {@link #addFirst}.
     *
     * @param e the element to push
     * @throws NullPointerException if the specified element is null
     */
    public void push(E e) {
        addFirst(e);
    }

    /**
     * Pops an element from the stack represented by this deque.  In other
     * words, removes and returns the first element of this deque.
     *
     * <p>This method is equivalent to {@link #removeFirst()}.
     *
     * @return the element at the front of this deque (which is the top
     *         of the stack represented by this deque)
     * @throws NoSuchElementException {@inheritDoc}
     */
    public E pop() {
        return removeFirst();
    }

四、Iterator 迭代器实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
   // 往头迭代 
    private class DeqIterator implements Iterator<E> {
        /**
         * Index of element to be returned by subsequent call to next.
         */
        private int cursor = head;  //头下标

        /**
         * Tail recorded at construction (also in remove), to stop
         * iterator and also to check for comodification.
         */
        private int fence = tail;  // 尾下标

        /**
         * Index of element returned by most recent call to next.
         * Reset to -1 if element is deleted by a call to remove.
         */
        private int lastRet = -1;

        public boolean hasNext() {
            return cursor != fence;
        }

        public E next() {
            if (cursor == fence)
                throw new NoSuchElementException();
            E result = elements[cursor];
            // This check doesn't catch all possible comodifications,
            // but does catch the ones that corrupt traversal
            if (tail != fence || result == null)
                throw new ConcurrentModificationException();
            lastRet = cursor;
            cursor = (cursor + 1) & (elements.length - 1); // 重新定位头下标
            return result;
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            if (delete(lastRet)) { // if left-shifted, undo increment in next()
                cursor = (cursor - 1) & (elements.length - 1);
                fence = tail;
            }
            lastRet = -1;
        }
    }

    // 往尾迭代 
    private class DescendingIterator implements Iterator<E> {
        /*
         * This class is nearly a mirror-image of DeqIterator, using
         * tail instead of head for initial cursor, and head instead of
         * tail for fence.
         */
        private int cursor = tail;  //尾下标
        private int fence = head;   // 头下标
        private int lastRet = -1;

        public boolean hasNext() {
            return cursor != fence;
        }

        public E next() {
            if (cursor == fence)
                throw new NoSuchElementException();
            cursor = (cursor - 1) & (elements.length - 1);
            E result = elements[cursor];
            if (head != fence || result == null)
                throw new ConcurrentModificationException();
            lastRet = cursor;
            return result;
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            if (!delete(lastRet)) {
                cursor = (cursor + 1) & (elements.length - 1);
                fence = head;
            }
            lastRet = -1;
        }
    }

五、总结

  • ArrayDeque默认构造初始化数组大小16。构造参数numElements,构建大小2幂方。这样做原因,快速查找下标。
  • ArrayDeque看做环形队列,大小2幂方, (head - 1) & (elements.length - 1)查找数组下标值,为性能方法&比取模性能好。
  • 指定删除元素(delete(int i))比较复杂点,必要时调整头和尾。这可能导致数组中的元素向后或向后移动。