5

我有两个相关的问题:

  1. 位运算符 >>> 意味着我们将二进制数移动了许多位,同时在最高有效位中填充 0。但是,为什么下面的操作会产生相同的数字:5>>>32 产生 5 和 -5>>>32 产生 -5。因为如果上面的描述是正确的,那么这两个操作都会产生 0 作为最终结果。

  2. 继续上面,根据 Effective Java 书,我们应该在计算哈希码(如果字段很长)时使用 (int) (f ^ (f >>> 32)) (如果字段很长)。我们为什么要这样做,解释是什么

4

3 回答 3

3

5可以表示为0101将其移动 1 位,即5>>>1这将导致0010=2

如果左侧操作数的提升类型是 int,则只有右侧操作数的五个最低位用作移位距离。就好像右手操作数经过位逻辑与运算符 & (§15.22.1) 与掩码值 0x1f。因此,实际使用的移位距离始终在 0 到 31 的范围内,包括 0 到 31。

当您使用 << 或 >> 运算符对整数进行移位且移位距离大于或等于 32 时,您将移位距离 mod 32(换句话说,您屏蔽除移位的低 5 位之外的所有位)距离)。这可能非常违反直觉。例如 (i> >> 32) == i,对于每个整数 i。您可能期望它将整个数字向右移动,对于正输入返回 0,对于负输入返回 -1,但事实并非如此;它只返回 i,因为 (i << (32 & 0x1f)) == (i << 0) == i。

于 2013-10-28T08:18:53.227 回答
2

我知道这个问题早就得到了回答,但我尝试了一个例子来获得更多的澄清,我想其他人也一样。

    long x = 3231147483648l;
    System.out.println(Long.toBinaryString(x));
    System.out.println(Long.toBinaryString(x >>> 32));
    System.out.println(Long.toBinaryString(x ^ (x >>> 32)));
    System.out.println(Long.toBinaryString((int) x ^ (x >>> 32)));

这打印 -

101111000001001111011001011110001000000000

1011110000

101111000001001111011001011110000011110000

1001111011001011110000011110000

正如@avrilfanomar 所提到的,这个 XOR 的前 32 位 long 与其他 32 位和无符号右移运算符帮助我们做到这一点。由于我们想在计算哈希码时使用这个长字段,因此直接将其转换longint意味着long仅在高 32 位不同的字段将为哈希码贡献相同的值。这可能意味着仅在该字段中不同的两个对象将具有相同的哈希码,并将存储在同一个存储桶中(例如解决冲突的列表),这会影响基于哈希的集合的性能。因此,这个操作。

于 2014-07-31T20:43:34.657 回答
2

您的第一个问题的答案是为什么 1>>32 == 1?

简而言之,第二个问题的答案是以这种方式使用整个 long 值(而不是它的一部分),并注意这可能是最快的方法。

于 2013-10-28T08:24:44.467 回答