Java中字节移位的奇怪行为
当我在Java中字节移位的奇怪行为,java,byte,bitwise-operators,bit-shift,binary-operators,Java,Byte,Bitwise Operators,Bit Shift,Binary Operators,当我在字节上使用位移位时,我注意到在使用无符号右移位(>)时得到了奇怪的结果。使用int,右移(有符号:>和无符号:>)的行为与预期一致: int min1 = Integer.MIN_VALUE>>31; //min1 = -1 int min2 = Integer.MIN_VALUE>>>31; //min2 = 1 但当我对字节执行相同操作时,无符号右移会发生奇怪的事情: byte b1 = Byte.MIN_VALUE; //b1
字节上使用位移位时,我注意到在使用无符号右移位(>
)时得到了奇怪的结果。使用int
,右移(有符号:>
和无符号:>
)的行为与预期一致:
int min1 = Integer.MIN_VALUE>>31; //min1 = -1
int min2 = Integer.MIN_VALUE>>>31; //min2 = 1
但当我对字节执行相同操作时,无符号右移会发生奇怪的事情:
byte b1 = Byte.MIN_VALUE; //b1 = -128
b1 >>= 7; //b1 = -1
byte b2 = Byte.MIN_VALUE; //b2 = -128
b2 >>>= 7; //b2 = -1; NOT 1!
b2 >>>= 8; //b2 = -1; NOT 0!
我认为可能是编译器在内部将字节
转换为int
,但似乎不足以解释这种行为
为什么在Java中字节的位移位是这样的?字节的移位运算符、short
和char
总是在int
上执行
因此,真正被移位的值是int
值-128
,如下所示
int b = 0b11111111_11111111_11111111_10000000;
当你做b2>>=7
您真正要做的是将上述值向右移动7位,然后仅考虑最后8位,返回到字节
向右移动7个位置后,我们得到
0b11111111_11111111_11111111_11111111;
当我们将其转换回字节时,我们只得到11111111
,这是-1
,因为byte
类型是有符号的
如果你想得到答案1,你可以移动31个位置而不需要标志扩展
byte b2 = Byte.MIN_VALUE; //b2 = -128
b2 >>>= 31;
System.out.println(b2); // 1
这正是因为byte
在执行按位操作之前要执行int
<代码>int-128
表示为:
11111111 11111111 11111111 10000000
因此,右移到7位或8位仍保留第7位1,因此结果为负字节值
比较:
System.out.println((byte) (b >>> 7)); // -1
System.out.println((byte) ((b & 0xFF) >>> 7)); // 1
通过b&0xFF
,所有最高位在移位前被清除,因此结果按预期产生。参考:
对每个操作数分别执行一元数字提升(§5.6.1)
以及:
如果操作数是编译时类型byte、short或char,则通过扩展原语转换将其提升为int类型的值
因此,在移位之前,字节
操作数提升为int
。值-128
为11111110000000
移位7或8次后,最低的8位都是1s,当分配给字节时,会发生缩小原语转换。参考:
有符号整数到整数类型T的缩小转换只会丢弃除n个最低阶位以外的所有位,其中n是用于表示类型T的位数
使用0xFF
是正确的解决方案+1.我不知道为什么我没有提出这个建议。难道他们没有想到这是一种疯狂的做事方式吗?