
1 public class ArrayDeque<E> extends AbstractCollection<E> 2 implements Deque<E>, Cloneable, Serializable
1 public interface Queue<E> extends Collection<E> {
2 // 增加一个元素到队尾,如果队列已满,则抛出一个IIIegaISlabEepeplian异常
3 boolean add(E e);
4 // 添加一个元素到队尾并返回true,如果队列已满,则返回false
5 boolean offer(E e);
6 // 移除并返回队列头部的元素,如果队列为空,则抛出一个NoSuchElementException异常
7 E remove();
8 // 移除并返问队列头部的元素,如果队列为空,则返回null
9 E poll();
10 // 返回队列头部的元素,如果队列为空,则抛出一个NoSuchElementException异常
11 E element();
12 // 返问队列头部的元素,如果队列为空,则返回null
13 E peek();
14 }
1 // 底层用数组存储元素 2 private transient E[] elements; 3 // 队列的头部元素索引(即将pop出的一个) 4 private transient int head; 5 // 队列下一个要添加的元素索引 6 private transient int tail; 7 // 最小的初始化容量大小,需要为2的n次幂 8 private static final int MIN_INITIAL_CAPACITY = 8;
1 /**
2 * 默认构造方法,数组的初始容量为16
3 */
4 public ArrayDeque() {
5 elements = (E[]) new Object[16];
6 }
7
8 /**
9 * 使用一个指定的初始容量构造一个ArrayDeque
10 */
11 public ArrayDeque( int numElements) {
12 allocateElements(numElements);
13 }
14
15 /**
16 * 构造一个指定Collection集合参数的ArrayDeque
17 */
18 public ArrayDeque(Collection<? extends E> c) {
19 allocateElements(c.size());
20 addAll(c);
21 }
22
23 /**
24 * 分配合适容量大小的数组,确保初始容量是大于指定numElements的最小的2的n次幂
25 */
26 private void allocateElements(int numElements) {
27 int initialCapacity = MIN_INITIAL_CAPACITY;
28 // 找到大于指定容量的最小的2的n次幂
29 // Find the best power of two to hold elements.
30 // Tests "<=" because arrays aren‘t kept full.
31 // 如果指定的容量小于初始容量8,则执行一下if中的逻辑操作
32 if (numElements >= initialCapacity) {
33 initialCapacity = numElements;
34 initialCapacity |= (initialCapacity >>> 1);
35 initialCapacity |= (initialCapacity >>> 2);
36 initialCapacity |= (initialCapacity >>> 4);
37 initialCapacity |= (initialCapacity >>> 8);
38 initialCapacity |= (initialCapacity >>> 16);
39 initialCapacity++;
40
41 if (initialCapacity < 0) // Too many elements, must back off
42 initialCapacity >>>= 1; // Good luck allocating 2 ^ 30 elements
43 }
44 elements = (E[]) new Object[initialCapacity];
45 }
2^1 = 10 2^2 = 100 2^3 = 1000 2^n = 1(n个0)
再来看下2^n-1的二进制是什么样子的:
2^1 - 1 = 01 2^2 - 1 = 011 2^3 - 1 = 0111 2^n - 1 = 0(n个1)
1 // 确保容量为2的n次幂,是capacity为大于initialCapacity的最小的2的n次幂 2 int capacity = 1; 3 while (capacity < initialCapacity) 4 capacity <<= 1;
那么这两种方法有什么区别呢?HashMap中的这种写法更容量理解,而ArrayDeque中的效果更高(最多经过4次位移和或操作+1次加一操作)。
4.入队(添加元素到队尾)
1 /**
2 * 增加一个元素,如果队列已满,则抛出一个IIIegaISlabEepeplian异常
3 */
4 public boolean add(E e) {
5 // 调用addLast方法,将元素添加到队尾
6 addLast(e);
7 return true;
8 }
9
10 /**
11 * 添加一个元素
12 */
13 public boolean offer(E e) {
14 // 调用offerLast方法,将元素添加到队尾
15 return offerLast(e);
16 }
17
18 /**
19 * 在队尾添加一个元素
20 */
21 public boolean offerLast(E e) {
22 // 调用addLast方法,将元素添加到队尾
23 addLast(e);
24 return true;
25 }
26
27 /**
28 * 将元素添加到队尾
29 */
30 public void addLast(E e) {
31 // 如果元素为null,咋抛出空指针异常
32 if (e == null)
33 throw new NullPointerException();
34 // 将元素e放到数组的tail位置
35 elements[tail ] = e;
36 // 判断tail和head是否相等,如果相等则对数组进行扩容
37 if ( (tail = (tail + 1) & ( elements.length - 1)) == head)
38 // 进行两倍扩容
39 doubleCapacity();
40 }
这里,( (tail = (tail + 1) & ( elements.length - 1)) == head)这句代码是关键,为什么会这样写呢。正常的添加元素后应该是将tail+1对不对,但是队列的删除和添加是不在同一端的,什么意思呢,我们画个图看一下。

2^1 = 10 2^2 = 100 2^3 = 1000 2^n = 1(n个0)
再来看下2^n-1的二进制是什么样子的:
2^1 - 1 = 01 2^2 - 1 = 011 2^3 - 1 = 0111 2^n - 1 = 0(n个1)
1 /**
2 * 数组将要满了的时候(tail==head)将,数组进行2倍扩容
3 */
4 private void doubleCapacity() {
5 // 验证head和tail是否相等
6 assert head == tail;
7 int p = head ;
8 // 记录数组的长度
9 int n = elements .length;
10 // 计算head后面的元素个数,这里没有采用jdk中自带的英文注释right,是因为所谓队列的上下左右,只是我们看的方位不同而已,如果上面画的图,这里就应该是left而非right
11 int r = n - p; // number of elements to the right of p
12 // 将数组长度扩大2倍
13 int newCapacity = n << 1;
14 // 如果此时长度小于0,则抛出IllegalStateException异常,什么时候newCapacity会小于0呢,前面我们说过了int值<<1越界
15 if (newCapacity < 0)
16 throw new IllegalStateException( "Sorry, deque too big" );
17 // 创建一个长度是原数组大小2倍的新数组
18 Object[] a = new Object[newCapacity];
19 // 将原数组head后的元素都拷贝值新数组
20 System. arraycopy(elements, p, a, 0, r);
21 // 将原数组head前的元素都拷贝到新数组
22 System. arraycopy(elements, 0, a, r, p);
23 // 将新数组赋值给elements
24 elements = (E[])a;
25 // 重置head为数组的第一个位置索引0
26 head = 0;
27 // 重置tail为数组的最后一个位置索引+1((length - 1) + 1)
28 tail = n;
29 }
1 /**
2 * 移除并返回队列头部的元素,如果队列为空,则抛出一个NoSuchElementException异常
3 */
4 public E remove() {
5 // 调用removeFirst方法,移除队头的元素
6 return removeFirst();
7 }
8
9 /**
10 * @throws NoSuchElementException {@inheritDoc}
11 */
12 public E removeFirst() {
13 // 调用pollFirst方法,移除并返回队头的元素
14 E x = pollFirst();
15 // 如果队列为空,则抛出NoSuchElementException异常
16 if (x == null)
17 throw new NoSuchElementException();
18 return x;
19 }
20
21 /**
22 * 移除并返问队列头部的元素,如果队列为空,则返回null
23 */
24 public E poll() {
25 // 调用pollFirst方法,移除并返回队头的元素
26 return pollFirst();
27 }
28
29 public E pollFirst() {
30 int h = head ;
31 // 取出数组队头位置的元素
32 E result = elements[h]; // Element is null if deque empty
33 // 如果数组队头位置没有元素,则返回null值
34 if (result == null)
35 return null;
36 // 将数组队头位置置空,也就是删除元素
37 elements[h] = null; // Must null out slot
38 // 将head指针往前移动一个位置
39 head = (h + 1) & (elements .length - 1);
40 // 将队头元素返回
41 return result;
42 }
1 /**
2 * 返回队列头部的元素,如果队列为空,则抛出一个NoSuchElementException异常
3 */
4 public E element() {
5 // 调用getFirst方法,获取队头的元素
6 return getFirst();
7 }
8
9 /**
10 * @throws NoSuchElementException {@inheritDoc}
11 */
12 public E getFirst() {
13 // 取得数组head位置的元素
14 E x = elements[head ];
15 // 如果数组head位置的元素为null,则抛出异常
16 if (x == null)
17 throw new NoSuchElementException();
18 return x;
19 }
20
21 /**
22 * 返回队列头部的元素,如果队列为空,则返回null
23 */
24 public E peek() {
25 // 调用peekFirst方法,获取队头的元素
26 return peekFirst();
27 }
28
29 public E peekFirst() {
30 // 取得数组head位置的元素并返回
31 return elements [head]; // elements[head] is null if deque empty
32 }
原文:http://www.cnblogs.com/vn2019/p/5174010.html