Java 有符号右移和无符号右移似乎具有相同的行为

Java 有符号右移和无符号右移似乎具有相同的行为,java,Java,为什么无符号右移逻辑右移和有符号右移算术右移对负数产生相同的结果 Log.v("-59 >>> 5 expected 6, actual", String.valueOf((byte)(-59 >>> 5))); Log.v("11000101 >>> 5 expected 00000110, actual",Integer.toBinaryString( -59 >>> 5)); Log.v("11000101 >&

为什么无符号右移逻辑右移和有符号右移算术右移对负数产生相同的结果

Log.v("-59 >>> 5 expected 6, actual", String.valueOf((byte)(-59 >>> 5)));
Log.v("11000101 >>> 5 expected 00000110, actual",Integer.toBinaryString( -59 >>> 5));
Log.v("11000101 >> 5 expected 00000110, actual",Integer.toBinaryString( -59 >> 5));
Android Studio Logcat输出

-59 >>> 5 expected 6, actual: -2

11000101 >>> 5 expected 00000110, actual: 111111111111111111111111110

11000101 >> 5 expected 00000110, actual: 11111111111111111111111111111110

这是正常的行为。任何具有负值的整数都有一个从无穷大1开始的二进制表示

如果你从-3开始,二进制表示如下:

...11 1101
1111 1101
1111 1111
所以如果我们把这个右移2,我们得到

...11 1111
现在是未设计/签名的右班。这取决于我们的整数中没有无限位数这一事实。假设我们将一个8位整数赋值为-3,如下所示:

...11 1101
1111 1101
1111 1111
如果我们进行有符号移位,它将查看MSB的最高有效位,即最左边的位,并在移位时保留该位的值。所以有符号的右移3看起来像这样:

...11 1101
1111 1101
1111 1111
相反,无符号右移不会检查MSB,只需右移并用零填充即可导致:

0011 1111
这正是您所看到的,但输出会截断前面的零

如果您不知道负整数为什么以这种方式存储

至于为什么b&0xff>>>5的行为会有所不同 java中的整数是32位的,这意味着二进制表示将有32位。您的-59将类似于以下二进制表示形式:

1111 1111 1111 1111 1111 1111 1100 0101 == -59
0000 0111 1111 1111 1111 1111 1111 1110 == -59 >>> 5
如果您现在将其与0xff一起使用,则会得到以下结果:

1111 1111 1111 1111 1111 1111 1100 0101 == -59
0000 0000 0000 0000 0000 0000 1111 1111 == 0xff
0000 0000 0000 0000 0000 0000 1100 0101 == -59 & 0xff
0000 0000 0000 0000 0000 0000 0000 0110 == (-59 & 0xff) >>> 5

右移运算符:-如果数字为负数,则填充1。如果数字为正数,则用0填充。
Unsigned Shift运算符:-无论数字的符号是什么,它都用0填充。

这是java VM错误吗?这不应该是您的第一个假设。请解释你为什么期望你所期望的。为什么它与右班相同?不是。111111111111111111111111110 != 1111111111111111111111111 0计算前导的1。int是32位,不像你想象的那样是8…二进制表示的-59是‭逻辑右移时为11000101‬结果应为00000110,即十进制6。但是当我使用>>>操作符时,得到的-2相当于‭11111110这表明已完成有符号右移,而不是逻辑移位。‬