Java的无符号位移右移(>>>)是有符号位移。

3

我想进行位右移操作,以便从一个字节中隔离出特定的位,因此我希望进行无符号移位,根据我的理解,“新”位应该是零。然而,我发现在我的测试中,“>>>”与“>>”没有任何区别。-128 >> 4 = -8,这是预期的结果,但是-128 >>> 4应该是8,但我仍然得到-8。

byte data = (byte)-128;
System.out.println((byte)(data >>> 4));
System.out.println((byte)(data >> 4));

感谢您的帮助。
2个回答

7
在这段代码中,无符号右移操作确实正在执行无符号右移操作;只是因为从byteint的隐式转换而被隐藏了。Java语言规范(§15.19)如此解释:
引用块:

操作符<<(左移)、>>(带符号右移)和>>>(无符号右移)称为移位运算符。移位运算符的左操作数是要移位的值;右操作数指定了移位距离。[...]每个操作数都分别执行一元数值推广(§5.6.1)。

一元数值提升意味着(§5.6.1):

引用块:

[...]如果操作数的编译时类型是byteshortchar,则通过扩展原始转换(§5.1.2)将其提升为int类型的值。

因此,您的代码按以下方式计算:
  • -128>>>的左操作数,它是一个byte值。根据规定,在执行移位操作之前将其提升为int类型,并变成 -128,在二进制中是0b11111111111111111111111110000000
  • 对此int值进行无符号右移操作,结果为268435448,在二进制中为0b00001111111111111111111111111000。请注意,最左边的四位为零,这是您从无符号右移期望的结果。
  • 然后将此结果明确转换为(byte)类型,得到结果为-8
使用REPL:
> byte b = -128;
> int shifted = b >>> 4;
> shifted
268435448
> (byte) shifted
-8

你所需要的行为,可以使用 & 0xFFbyte 转换为 int 进行“无符号”转换:

> ((b & 0xFF) >>> 4)
8

1
谢谢!我现在完全明白了!它将其转换为Int,然后强制转换为byte截断了剩余的部分和“新”的零! - Funtime60

1

有符号右移位运算符'>>'使用符号位来填充尾部位置,而无符号右移位运算符'>>'不使用符号位来填充尾部位置。它总是用0来填充尾部位置。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接