ArrayDeque——循环数组之找下一个元素的正确位置
内部的实例变量:
private transient E[] elements; // 用于存储元素的数组
privata transient int head; // 头
privata transient int tail; // 尾
如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。
构造方法(其一)
public ArrayDeque(Collection<? extends E> c){
allocateElements(c.size); // 该方法用于计算该分配的数组的长度
addAll(c);
allocateElements(int numElements)
该方法计算逻辑:
-
如果numElements小于8,就是8
-
如果numElements大于等于8,分配的实际长度是严格大于numElements并且为2的整数次幂的最小数。比如:numElements为10,则实际分配16,如果numElements为32则为64。
是2的幂次数,是为了更有效率的获取数组中下一个元素的正确位置。严格大于numElements,是因为循环数组必须时刻至少留一个空位,tail指向下一个空位,为了容纳numElements个元素,至少需要numElements+1个位置
addAll(E e)
addAll只是循环调用了add方法;
add:
public boolan add(E e){
addLast(e);
return true;
}
addLast(E e)
public void addLast(E e){
if(e == null)
throw new NullPointerException();
elements[tail] = e; // 将元素添加到tail处
if((tail = (tail +1 ) & (element.length-1)) == head)
doubleCapacity
}
- tail = (tail +1 ) & (element.length-1)—— 将tail指向下一个位置(tail的下一个位置是 (tail +1 ) & (element.length-1))
- (tail = (tail +1 ) & (element.length-1)) == head 时说明队列满了
神奇的操作:
进行与操作保证了索引在正确范围,与(element.length-1)相与就可以得到下一个正确位置,是因为elements.length时2的幂次方,(element.length-1)的后几位全是1,无论是证书还是附属,与(element.length-1)相与都能得到期望的下一个正确位置;
这种操作是循环数组中的常见操作,效率很高。
ps:与操作:将数转换为二进制,都为1时为1,其他情况都为0,得到值后再转为10进制
如:elements.length = 8,则(element.length-1) = 7,二进制为0111,对于8,与7相与,结果为0.