Java 集合源码解析系列:
- 拆行解码 Java 集合源码之总览
- 拆行解码 Java 集合源码之 Collection 的三大体系
- 拆行解码 Java 集合源码之迭代器
- 拆行解码 Java 集合源码之 ArrayList
- 拆行解码 Java 集合源码之 LinkedList
- 拆行解码 Java 集合源码之 HashMap
- 拆行解码 Java 集合源码之 Hashtable
- 拆行解码 Java 集合源码之 LinkedHashMap
- 拆行解码 Java 集合源码之 PriorityQueue
- 拆行解码 Java 集合源码之 ArrayDeque
特性
- 环形队列。
-
初始容量 16
指定容量时,因为是环形队列,所以数组末尾必须有个空位,用作头尾判空或满的依据。
(numElements < 1) ? 1 : (numElements == Integer.MAX_VALUE) ? Integer.MAX_VALUE : numElements + 1
- 保存双端索引:head 和 tail。
- 为空时:0 <= head = tail < elements.length
- 满:length - head = tail
- elements[tail] 一直为 null
- 默认扩容容量:
(oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1)
。
单个添加后,才去扩容。
- 最关键的点就是维护好 head 和 tail 关系。
构造函数
public class ArrayDeque<E> extends AbstractCollection<E>
implements Deque<E>, Cloneable, Serializable {
transient Object[] elements;
/**
* 空 :0 <= head = tail < elements.length
* 满 : elements.length - head = tail
*/
transient int head;
/**
* elements[tail] 在任意操作后,对外展示时, 一定是 null
*/
transient int tail;
public ArrayDeque() {
elements = new Object[16];
}
public ArrayDeque(int numElements) {
// 尽量会保留一个空槽
elements =
new Object[(numElements < 1) ? 1 :
(numElements == Integer.MAX_VALUE) ? Integer.MAX_VALUE :
numElements + 1];
}
public ArrayDeque(Collection<? extends E> c) {
this(c.size());
copyElements(c);
}
}
头尾索引的维护
一般 modulus = elements.length。
/**
* Circularly increments i, mod modulus.
* Precondition and postcondition: 0 <= i < modulus.
*/
static final int inc(int i, int modulus) {
if (++i >= modulus) i = 0;
return i;
}
/**
* Circularly decrements i, mod modulus.
* Precondition and postcondition: 0 <= i < modulus.
*/
static final int dec(int i, int modulus) {
if (--i < 0) i = modulus - 1;
return i;
}
/**
* Circularly adds the given distance to index i, mod modulus.
* Precondition: 0 <= i < modulus, 0 <= distance <= modulus.
* @return index 0 <= i < modulus
*/
static final int inc(int i, int distance, int modulus) {
if ((i += distance) - modulus >= 0) i -= modulus;
return i;
}
/**
* Subtracts j from i, mod modulus.
* Index i must be logically ahead of index j.
* Precondition: 0 <= i < modulus, 0 <= j < modulus.
* @return the "circular distance" from j to i; corner case i == j
* is disambiguated to "empty", returning 0.
*/
static final int sub(int i, int j, int modulus) {
if ((i -= j) < 0) i += modulus;
return i;
}
/**
* Returns element at array index i.
* This is a slight abuse of generics, accepted by javac.
*/
@SuppressWarnings("unchecked")
static final <E> E elementAt(Object[] es, int i) {
return (E) es[i];
}
添加
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
final Object[] es = elements;
es[head = dec(head, es.length)] = e;
if (head == tail)
// 添加后扩容
grow(1);
}
public void addLast(E e) {
if (e == null)
throw new NullPointerException();
final Object[] es = elements;
es[tail] = e;
if (head == (tail = inc(tail, es.length)))
// 添加后扩容
grow(1);
}
public boolean addAll(Collection<? extends E> c) {
final int s, needed;
if ((needed = (s = size()) + c.size() + 1 - elements.length) > 0)
grow(needed);
copyElements(c);
return size() > s;
}
private void copyElements(Collection<? extends E> c) {
c.forEach(this::addLast);
}
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
public boolean offerLast(E e) {
addLast(e);
return true;
}
移除
public E removeFirst() {
E e = pollFirst();
if (e == null)
throw new NoSuchElementException();
return e;
}
/**
* @throws NoSuchElementException {@inheritDoc}
*/
public E removeLast() {
E e = pollLast();
if (e == null)
throw new NoSuchElementException();
return e;
}
public E pollFirst() {
final Object[] es;
final int h;
E e = elementAt(es = elements, h = head);
if (e != null) {
es[h] = null;
head = inc(h, es.length);
}
return e;
}
public E pollLast() {
final Object[] es;
final int t;
E e = elementAt(es = elements, t = dec(tail, es.length));
if (e != null)
es[tail = t] = null;
return e;
}
扩容
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int needed) {
// overflow-conscious code
final int oldCapacity = elements.length;
int newCapacity;
// Double capacity if small; else grow by 50%
int jump = (oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1);
if (jump < needed
|| (newCapacity = (oldCapacity + jump)) - MAX_ARRAY_SIZE > 0)
newCapacity = newCapacity(needed, jump);
final Object[] es = elements = Arrays.copyOf(elements, newCapacity);
// Exceptionally, here tail == head needs to be disambiguated
if (tail < head
// 因为是添加后扩容, 所以需要判断 tail == head 的歧义(可能是满,违反了 tail 一定是 null 的规则)
|| (tail == head && es[head] != null)) {
// wrap around; slide first leg forward to end of array
// ++++++tail-------head++++++|------ 或 ++++++++++++head&tail++++++|------
int newSpace = newCapacity - oldCapacity;
System.arraycopy(es, head,
es, head + newSpace,
oldCapacity - head);
for (int i = head, to = (head += newSpace); i < to; i++)
es[i] = null;
// 处理后:++++++tail-------------head++++++ 或 ++++++++++++tail------head++++++
}
}
/** Capacity calculation for edge conditions, especially overflow. */
private int newCapacity(int needed, int jump) {
final int oldCapacity = elements.length, minCapacity;
if ((minCapacity = oldCapacity + needed) - MAX_ARRAY_SIZE > 0) {
if (minCapacity < 0)
throw new IllegalStateException("Sorry, deque too big");
return Integer.MAX_VALUE;
}
if (needed > jump)
return minCapacity;
return (oldCapacity + jump - MAX_ARRAY_SIZE < 0)
? oldCapacity + jump
: MAX_ARRAY_SIZE;
}
指定删除
涉及到元素向前向后挪移、头尾索引的维护。
力求挪移最少的元素。
批量删除
利用位图,批量查询符合条件的,批量删除。
避免 头尾索引的重复计算。