在Java中,-4>> 2给出-1但-5>> 2给-2。谁能解释为什么? 以下是示例代码:
byte r=-5;
r>>=2;
System.out.println(r);
同样在这种情况下>>和>>>运营商给出了相同的答案。任何人都可以解释一下吗?
答案 0 :(得分:5)
你可以看一下这些位。使用two's complement表示法,-4
和-5
的位是,为简洁起见仅显示最后8位:
-4: 1111 1100
-5: 1111 1011
位移到右侧2位置,带符号扩展名:
-4 >> 2: 1111 1111 (-1)
-5 >> 2: 1111 1110 (-2)
通常情况下,您认为>>>
没有使用符号扩展名,这是正确的,但在这种情况下:
r >>>= 2;
...对于使用二进制数字提升的位移操作,值r
被提升为int
,但是复合赋值运算符将返回的值转换回byte
,并且移入的零"消失"。
byte r = -5; // 1111 1100
r >>>= -2; // promoted to int: 11111111 11111111 11111111 11111010
// bit shift: 00111111 11111111 11111111 11111110
// cast back to byte: 11111110 (-2)
JLS, Section 15.26.2,讨论了在复合赋值运算符中完成的转换操作:
E1 op = E2形式的复合赋值表达式等效于E1 =(T)((E1)op(E2)),其中T是E1的类型,但E1仅被评估一次。
也就是说,在这种情况下,位移的结果被转换回byte
。
当r
的值为-4
时,会发生相同的强制回送操作。
请注意,如果分配部分尚未完成,那么您将看不到相同的答案,因为它不会将结果强制转换回byte
:
System.out.println(r >>> 2);
然后你会看到:
1073741822
答案 1 :(得分:2)
任何人都可以解释为什么(-4>>> 2是-1,-5>> 2是-2)?
二进制-4字节如下所示:11111100
。当你在扩展符号的同时向右移动时,你得到11111111
(左边的是符号扩展,即在向左移动时保持符号位)。这是两个补码表示中的-1
。
二进制-5字节如下所示:11111011
。当你在伸出标志的同时向右移动时,你会得到11111110
(同样,左边的是符号扩展名)。这是-2。
>>
和>>>
运营商给出相同的答案。任何人都可以解释一下吗?
移位以整数执行。当您使用>>>
转换-4
而不使用符号扩展名时,您会获得00111111111111111111111111111111
。当您将其转换为byte
时,您会切断前24位,最后将低8位全部设置为1
。同样适用于>>>
的{{1}}。
答案 2 :(得分:0)
字节-4 == 0xFC。如果将算术右移(即保留符号位)2位,则得到0xFF,即-1。
-5 == 0xFB。如果将算术右移2位,则得到0xFE,即-2。
答案 3 :(得分:0)
在负数的情况下,在内存中,它们使用称为二进制补码的技术进行存储。在这个例子中,5是:0 ... 0101(我为了长度而删除了很多0 所以当你转移0101两次时,你得到:
0101 >> 0010
0010 >> 0001
0001是1
在二进制补码中你有1 ... 1011(反向所有位然后加一个二进制1) 所以当你转移1011时你已经
了1011 >> 1101 (we carry the other 1's)
1101 >> 1110 (we carry the other 1's)
1 ... 1110是-2
的负数答案 4 :(得分:0)
Java使用二进制补码格式来表示负数。
-5表示为二进制的11111011
,当右位移位2位时变为11111110
,即-2。类似地,-4表示为11111100
,当右位移2时变为11111111
,十进制为-1。
>>
和>>>
看起来相同的原因是因为>>>
运算符是整数的逻辑右移,而不是字节。因此,java在执行逻辑移位之前将类型转换为int,然后将bitstring截断为仅最低有效8位。因为-5的整数表示是11111111111111111111111111111011
而右边的逻辑移位2是11111111111111111111111111111110
,它是11111110
的字节的类型转换,即-2。
如果您尝试以下代码,则会看到结果:
byte r = -5;
System.out.println(r >> 2);
System.out.println(r >>> 2);
r>>>=2;
System.out.println(r);