5

当我在 上使用位移时byte,我注意到在使用无符号右移 ( >>>) 时我得到了奇怪的结果。使用int时,右移(有符号:>>和无符号>>>:)都按预期运行:

    int min1 = Integer.MIN_VALUE>>31; //min1 = -1
    int min2 = Integer.MIN_VALUE>>>31; //min2 = 1

但是当我对 做同样的byte事情时,无符号右移会发生奇怪的事情:

    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!

我认为可能是编译器在内部将其转换byteint,但似乎不足以解释这种行为。

为什么移位在 Java 中以字节的方式表现?

4

3 回答 3

6

byte发生这种情况正是因为被提升为之前int执行的按位运算。int -128表示为:

11111111 11111111 11111111 10000000

因此,右移到 7 位或 8 位仍然会留下第 7 位 1,因此结果会缩小为负值byte

相比:

System.out.println((byte) (b >>> 7));           // -1
System.out.println((byte) ((b & 0xFF) >>> 7));  //  1

通过b & 0xFF,所有最高位在移位之前被清除,因此结果按预期产生。

于 2016-04-06T15:13:30.317 回答
3

和的移位运算符byte总是在 上完成。shortcharint

因此,真正被移动的值是intvalue -128,它看起来像这样

int b = 0b11111111_11111111_11111111_10000000;

当您执行b2 >>= 7;实际操作时,将上述值向右移动 7 位,然后仅考虑最后 8 位,然后将其转换回 a byte

向右移动 7 个位置后,我们得到

        0b11111111_11111111_11111111_11111111;

当我们将它转​​换回一个字节时,我们只得到11111111,即-1,因为byte类型是有符号的。

如果你想得到答案 1,你可以在没有符号扩展的情况下移动 31 个位置。

byte b2 = Byte.MIN_VALUE; //b2 = -128
b2 >>>= 31;
System.out.println(b2);   // 1
于 2016-04-06T15:12:43.823 回答
0

请参阅JLS 15.19 移位运算符

一元数字提升(第 5.6.1 节)分别对每个操作数执行。

5.6.1 一元数字提升中:

如果操作数是编译时类型 byte、short 或 char,则通过扩展原语转换将其提升为 int 类型的值

因此,您的操作数在移位之前byte被提升。int值为。-128_11111111111111111111111110000000

移位 7 或 8 次后,最低 8 位全为 1,当分配给 a 时byte,会发生窄化原语转换。请参阅JLS 5.1.3 Narrowing Primitive Conversion

有符号整数到整数类型 T 的窄化转换只会丢弃除n 个最低位之外的所有位,其中 n 是用于表示类型 T 的位数。

于 2016-04-06T15:17:05.307 回答