为什么要使用i =(i + 1)&面具,面具是0b1111?

时间:2017-08-24 11:21:18

标签: java bit-manipulation

当我找到这个实现时,我正在查看ArrayDeque.contains(Object o)的源代码:

/**
 * Returns {@code true} if this deque contains the specified element.
 * More formally, returns {@code true} if and only if this deque contains
 * at least one element {@code e} such that {@code o.equals(e)}.
 *
 * @param o object to be checked for containment in this deque
 * @return {@code true} if this deque contains the specified element
 */
public boolean contains(Object o) {
    if (o == null)
        return false;
    int mask = elements.length - 1;
    int i = head;
    Object x;
    while ( (x = elements[i]) != null) {
        if (o.equals(x))
            return true;
        i = (i + 1) & mask;
    }
    return false;
}

这里,数组大小是2的指数,因此mask应该是一个全1的二进制数。在我看来,i = (i + 1) & maski = i + 1完全相同。谁能告诉我为什么这样实施呢?

3 个答案:

答案 0 :(得分:2)

我不熟悉实现,但这看起来像一个“循环数组”。 head是第一个元素的索引,通过递增和屏蔽边界周围的迭代循环。

数组中的“last”插槽始终为空(== null),如果找不到该对象,将结束迭代,并返回false

答案 1 :(得分:2)

这是为了包装一个计数器。正如您已经说过的,如果元素的数量是2的幂,那么AuthProvider将是所有位1。

elements.length -1

现在我们再次增加

mask = 7  // we assume a elements.length of 8
x = (x + 1) & mask  // will be 7 and 7, so result is 7

实现相同结果的其他可能更具可读性的方法是:

x = (x + 1) & mask // now it is 8 and 7, so result will be zero

但屏蔽它只是速度(不是可读性)的改进。

答案 2 :(得分:1)

此行应用模数限制增量操作的快速版本。

i = (i + 1) & (length - 1);

长度为8,你得

0 -> 1
1 -> 2
2 -> 3
3 -> 4
4 -> 5
5 -> 6
6 -> 7
7 -> 0

你知道时钟的类似行为(差不多,因为我们通常以1而不是0开始时钟),

有一个约束,长度必须能写成2 ^ n,2,4,8,16,32,64,128,256,512,1024,....

这是有效的,因为(2 ^ n)-1的位表示是具有n个的掩码。 例如(2 ^ 5)-1是二进制0b00011111。

任何数字0< = x< 2 ^ n将通过掩码(2 ^ n)-1而不进行更改。当应用蒙版时,数字2 ^ n将被设置为0.

更一般的方法是使用modulo%。但是modulo通常比比特操作慢得多,例如"和" (&)