Java位移位奇异性
Java有2个用于右移的位移位运算符:Java位移位奇异性,java,debugging,bit-shift,Java,Debugging,Bit Shift,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 这似乎相当简单,所以有人能向我解释一下,为什么这段代码,当bar的值为-128时,foo的值为-2: byte foo = (byte)((bar & (
>> shifts right, and is dependant on the sign bit for the sign of the result
>>> shifts right and shifts a zero into leftmost bits
这似乎相当简单,所以有人能向我解释一下,为什么这段代码,当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而不是0被移到左边的位置,这是因为&实际上正在执行升级到
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的负载。AFAIK,在Java中,大多数操作符(+、-、>>,等等)不能处理小于
int
s的任何东西。因此,按位移位和&
在后台将值隐式转换为int
,然后通过显式转换返回到字节。最后一次强制转换去掉高位中的零
要获得您期望的结果,请尝试在int
s上执行此操作。其他人已经告诉您原因,但我将进一步细分,并提供真正问题的答案
byte foo = (byte)((bar & ((byte)-64)) >>> 6);
由于&operator会将所有内容提升为int,因此这实际上是:
byte foo = (byte)(((int)bar & (int)((byte)-64)) >>> 6);
如果条为-128,则(int)条为0xFFFF80,然后与0xFFFFC0进行&'。。。也就是:0xFFFF80,然后向右移动6个位置,得到:0x3FFFFFFE
正确的答案非常简单:
byte foo = (byte)((bar & 0xC0) >> 6);
对于&操作,bar被提升为int,因此该int中只剩下原始字节的前两位。然后将其右移6位,并将其转换回字节。@Martin:不,因为移位也会起到提升作用。将在一分钟内使用解决方案进行编辑。非常感谢,显然您的bitfoo比我的大;)注意,此处不需要>>>,因为符号位已被清除。另外,最初的海报需要顶部的两位,即0xC0。你说0xC0,Jon说0xD0。我想我必须在这里检查你的逻辑…@Martin:0xC0是正确的。我已经确定了我的答案。多么尴尬:)我开始得出那个结论,我开始三次检查它,从不怀疑伟大的双向飞碟