简介
双端队列是一种特殊的队列,它的两端都可以进出元素,故而得名双端队列。
ArrayDeque
是一种以循环数组方式实现的双端队列,它是非线程安全的。
它既可以作为队列也可以作为栈。
继承体系
ArrayDeque
实现了 Deque
接口, Deque
接口继承自 Queue
接口,它是对 Queue
的一种增强。
同时实现了 Serializable
和 Cloneable
接口,可以进行序列化和克隆。
源码解读
主要属性
// 存储元素的数组 transient Object[] elements; // non-private to simplify nested class access // 队列头位置 transient int head; // 队列尾位置 transient int tail; // 最小初始容量 private static final int MIN_INITIAL_CAPACITY = 8; // 序列号 private static final long serialVersionUID = 2340985798034038923L;
head
指向头元素
tail
指向尾元素的下一个位置
这里注意到, head
, tail
, elements
属性都被 transient
修饰,不会参与序列化。
可能会有疑问, **elements**
要是不参与序列化,集合内的数据不就无法持久化吗。
这个问题先放在这里,讲完 ArrayList
扩容原理之后再进行回答。
构造方法
// 默认构造方法,初始容量为16 public ArrayDeque() { elements = new Object[16]; } // 指定元素个数初始化 public ArrayDeque(int numElements) { allocateElements(numElements); } // 将集合c中的元素初始化到数组中 public ArrayDeque(Collection<? extends E> c) { allocateElements(c.size()); addAll(c); } // 初始化数组 private void allocateElements(int numElements) { elements = new Object[calculateSize(numElements)]; } // 计算容量,这段代码的逻辑是算出大于numElements的最接近的2的n次方且不小于8 // 比如,3算出来是8,9算出来是16,33算出来是64 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; }
通过构造方法,我们知道默认初始容量是16,最小容量是8。
这里比较有意思的是 calculateSize
容量计算方法,本质是为了获取大于当前数值的最小的2的幂,比如 3 算出来是 8