Java 有 2 个用于右移的移位运算符:
>> shifts right, and is dependant on the sign bit for the sign of the result
>>> shifts right and shifts a zero into leftmost bits
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/op3.html
这看起来相当简单,所以任何人都可以向我解释为什么这段代码在给 bar 赋值 -128 时为 foo 生成 -2 的值:
byte foo = (byte)((bar & ((byte)-64)) >>> 6);
这样做的目的是获取一个 8 位字节,最左边 2 位的掩码,并将它们移到最右边的 2 位。即:
initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b10000000
0b10000000 >>> 6 = 0b00000010
结果实际上是-2,也就是
0b11111110
即。 1 而不是零被移到左边的位置
最佳答案
这是因为 & 实际上正在执行对 int
的提升 - 这留下了非常多的“1”位。然后向右移动,将最左边的 2 位保留为 0,但随后通过转换回字节忽略那些最左边的位。
当您分离操作时,这会变得更清楚:
public class Test
{
public static void main(String[] args)
{
byte bar = -128;
int tmp = (bar & ((byte)-64)) >>> 6;
byte foo = (byte)tmp;
System.out.println(tmp);
System.out.println(foo);
}
}
打印
67108862
-2
所以再次进行位运算:
initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b11111111111111111111111110000000 // it's an int now
0b10000000 >>> 6 = 0b00111111111111111111111111100000 // note zero-padding
(byte) (0b10000000 >>> 6) = 11100000 // -2
即使您从 & 操作中得到正确的结果(通过在该点进行强制转换),>>>
无论如何都会首先将第一个操作数提升为 int
。
编辑:解决方案是改变你掩盖事物的方式。不是用 -64 掩码,而是用 128+64=192=0xc0 掩码:
byte foo = (byte)((bar & 0xc0) >>> 6);
这样您实际上只剩下您想要的两位,而不是在最高有效的 24 位中加载 1。
关于Java 移位奇怪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2173205/