ArrayDeque
ArrayDeque和LinkedList是Deque的两个通用实现,在使用Queue时,由于Queue只是一个接口,因此创建Queue时也会使用ArrayDeque
为了实现在数组两端进行操作元素的需求,因此ArrayDeque使用循环数组作为底层数据结构,同时,ArrayDeque中定义了head和tail两个指针指向头和尾
因为是循环数组,所以head可能比tail大,head指向第一个有效元素,tail指向尾部第一个可以插入元素的空位。
插入元素
因为是循环数组,扩容比较棘手,因此扩容操作是在插入操作完成之后进行的。
tail永远执行一个空位置,所以插入操作永远是有空余位置的。
下标越界直接取余就行。
public void addFirst(E e) {
if (e == null)//不允许放入null
throw new NullPointerException();
elements[head = (head - 1) & (elements.length - 1)] = e;//2.下标是否越界
if (head == tail)//1.空间是否够用
doubleCapacity();//扩容
}
扩容操作
扩容操作的逻辑是申请一个更大的数组(两倍),然后使用System.arraycopy进行数据拷贝,拷贝的时候拷贝到新数组的头部。
private void doubleCapacity() {
assert head == tail;
int p = head;
int n = elements.length;
int r = n - p; // head右边元素的个数
int newCapacity = n << 1;//原空间的2倍
if (newCapacity < 0)
throw new IllegalStateException("Sorry, deque too big");
Object[] a = new Object[newCapacity];
//第一次复制head右边的元素
System.arraycopy(elements, p, a, 0, r);
//第二次复制head左边的元素
System.arraycopy(elements, 0, a, r, p);
elements = (E[])a;
head = 0;
tail = n;
}
删除操作
删除只需要挪动下标,然后原来位置置null(方便GC回收)
public E pollFirst() {
int h = head;
E result = elements[head];
if (result == null)
return null;
elements[h] = null;//方便GC回收
head = (head + 1) & (elements.length - 1);//下标越界处理
return result;
}
快速失败
ArrayDeque不是快速失败的集合,也不是安全失败的集合
ArrayDeque的迭代器是弱一致性的,不是快速失败的。它允许在迭代期间对集合进行修改而不会抛出异常,但这种修改可能不会被迭代器所反映出来。
快速失败和安全失败的区别
快速失败:使用modCount记录结构版本,发现接口修改直接抛出ConcurrentModificationException
安全失败:创建快照副本,保证迭代器迭代的时候不会受到结构修改的影响。
标签:head,ArrayDeque,int,解读,tail,源码,null,elements From: https://www.cnblogs.com/lilizzyy/p/18374131