以下代码来自标准java库中的ArrayDeque。我选择它有点随意,因为在整个代码中有很多这个想法的例子。
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
elements[head = (head - 1) & (elements.length - 1)] = e;
if (head == tail)
doubleCapacity();
}
基本上,当我读到它时,head的值减1,然后按element.length减1来逐位“anded”。此操作确定数组的哪个索引将保存新值e,并允许循环回送到数组的开头。好到目前为止(我希望没错)。
但接下来我们就来了:
if (head == tail) doubleCapacity();
头部和尾部是整齐的。即使它们在按位“anded”(意味着数组已满且需要扩展)之后将等于数组中的相同位置,这也不会使它们与int相等(这是正在测试的,对吧?)。
所以...我不明白这是如何运作的。
有人可以帮忙吗?
编辑澄清我指的是数组的索引,而不是它的任何元素。
答案 0 :(得分:3)
head
和tail
最初引用数组的第一个索引 - 0。
默认情况下,后备阵列的初始长度为16,并且始终为2的幂。这对于您引用的代码片段非常重要。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
^
head
tail
现在假设您在队列末尾添加了15个元素。每次向末尾添加元素时,tail
索引都会递增,因此在添加15个元素后,您将得到:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
^ ^
head tail
此时,除15之外的所有数组索引都被占用。
现在我们来看你引用的代码:
当你调用addFirst
时,head
应该递减(必要时回绕到数组的末尾),并且新元素被添加到{{1的新值的索引处}}
由于head
为0,head
,head
的新值为(head - 1) & (elements.length - 1)
或(转换为二进制)-1 & 15
,等于15,数组的最后一个索引。
此时,11111111111111111111111111111111 & 00000000000000000000000000001111
和head
都包含数组的最后一个索引 - 15.
tail
这意味着阵列已满,必须加倍。
这里要注意的重要一点是0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
^
head
tail
相当于(head - 1) & (elements.length - 1)
。这是真的,因为(head - 1) % elements.length
是2的幂。