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.我不知道为什么我没有提出这个建议。难道他们没有想到这是一种疯狂的做事方式吗?