考虑以下java代码片段
byte b=(byte) 0xf1;
byte c=(byte)(b>>4);
byte d=(byte) (b>>>4);
输出:
c=0xff
d=0xff
预期输出:
c=0x0f
如何?因此,1111 0001
在无符号右移后,二进制中的 b 为 b但为什么会这样 呢?0000 1111
0x0f
0xff
问题是所有参数int
在移位操作发生之前首先被提升:
byte b = (byte) 0xf1;
b
有符号,所以它的值为-15。
byte c = (byte) (b >> 4);
b
首先将符号扩展为整数-15 = 0xfffffff1
,然后右移到并被强制转换为0xffffffff
截断。0xff
byte
byte d = (byte) (b >>> 4);
b
首先将符号扩展为整数-15 = 0xfffffff1
,然后右移到并被强制转换为0x0fffffff
截断。0xff
byte
你可以做得到(b & 0xff) >>> 4
想要的效果。
我猜这b
是转移前的标志int
。
所以这可能会按预期工作:
(byte)((0x000000FF & b)>>4)
根据按位和位移运算符:
无符号右移运算符“>>>”将零移到最左边的位置,而“>>”之后的最左边的位置取决于符号扩展。
因此,b >> 4
您转换1111 0001
为1111 1111
(b 为负数,因此它附加1
) 即0xff
.
Java 试图通过定义两个不同的移位运算符来避免显式支持无符号基本类型。
该问题讨论了无符号右移,但示例同时执行(有符号和无符号),并显示了有符号移位(>>)的值。
您的计算对于无符号移位 (>>>) 是正确的。
字节操作数在移位之前提升为 int。
请参阅https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.19
一元数字提升(第 5.6.1 节)分别对每个操作数执行。(二进制数字提升(第 5.6.2 节)不在操作数上执行。)
和https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.1
否则,如果操作数是编译时类型 byte、short 或 char,则通过扩展原语转换(第 5.1.2 节)将其提升为 int 类型的值。
字节 b=(字节) 0xf1;
如果 (b<0)
d = (字节) ((字节) ((字节)(b>>1)&(字节)(0x7F)) >>>3);
别的
d = (字节)(b>>>4);
首先,检查值:如果值为负。右移一次,&0x7F,变为正数。然后您可以轻松地进行其余的右移(4-1 = 3)。
If the value is positive, make all right shift with >>4 or >>>4. It does'nt make no difference in result nor any problem of right shift.