在数组操作中混合按位和普通操作(java)

时间:2017-06-27 19:03:37

标签: java arrays

以下代码来自标准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相等(这是正在测试的,对吧?)。

所以...我不明白这是如何运作的。

有人可以帮忙吗?

编辑澄清我指的是数组的索引,而不是它的任何元素。

1 个答案:

答案 0 :(得分:3)

headtail最初引用数组的第一个索引 - 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,headhead的新值为(head - 1) & (elements.length - 1)或(转换为二进制)-1 & 15,等于15,数组的最后一个索引。

此时,11111111111111111111111111111111 & 00000000000000000000000000001111head都包含数组的最后一个索引 - 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的幂。