考虑以下Java代码片段
byte b=(byte) 0xf1;
byte c=(byte)(b>>4);
byte d=(byte) (b>>>4);
输出:
c=0xff
d=0xff
预期产出:
c=0x0f
如何?
作为二进制1111 0001
中的b
无符号右移后0000 1111
因此0x0f
,但为什么0xff
如何?
答案 0 :(得分:38)
问题是所有参数在转换操作发生之前首先被提升为int
:
byte b = (byte) 0xf1;
b
已签名,因此其值为-15。
byte c = (byte) (b >> 4);
b
首先符号扩展为整数-15 = 0xfffffff1
,然后向右移动到0xffffffff
,并通过强制转换为0xff
到byte
。< / p>
byte d = (byte) (b >>> 4);
b
首先符号扩展为整数-15 = 0xfffffff1
,然后向右移动到0x0fffffff
,并通过强制转换为0xff
到byte
。< / p>
您可以(b & 0xff) >>> 4
来获得所需的效果。
答案 1 :(得分:4)
我猜在移位之前,b
符号已扩展为int
。
所以这可能会按预期工作:
(byte)((0x000000FF & b)>>4)
答案 2 :(得分:1)
根据Bitwise and Bit Shift Operators:
无符号右移运算符“&gt;&gt;&gt;”将零移动到最左边的位置,而在“&gt;&gt;”之后的最左边的位置移动取决于符号扩展。
因此,使用b >> 4
,您将1111 0001
转换为1111 1111
(b为负数,因此它附加1
),即0xff
。
答案 3 :(得分:0)
Java试图通过定义两个不同的移位运算符来避免明确支持无符号基本类型。
问题涉及无符号右移,但示例同时执行(有符号和无符号),并显示有符号移位的值(&gt;&gt;)。
您的计算适用于无符号移位(&gt;&gt;&gt;)。
答案 4 :(得分:0)
字节操作数在移位之前被提升为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,则通过扩展原始转换将其提升为int类型的值(第5.1.2节)。
答案 5 :(得分:-1)
字节b =(字节)0xf1;
如果(b <0)
d =(字节)((字节)((字节)(b >> 1)&(字节)(0x7F))>>> 3);
其他
d =(字节)(b >>> 4);
首先,检查值: 如果值为负。右移,然后&0x7F,它将变为正。那么您可以轻松进行其余的右移(4-1 = 3)。
如果该值为正,则用>> 4或>>> 4进行右移。它既不会影响结果,也不会造成右移问题。