Java位移位的奇怪之处
Java 有 2 个用于右移的位移运算符:
>> shifts right, and is dependant on the sign bit for the sign of the result
>>> shifts right and shifts a zero into leftmost bits
http://java .sun.com/docs/books/tutorial/java/nutsandbolts/op3.html
这看起来相当简单,所以任何人都可以向我解释为什么这段代码在给 bar 赋予 -128 的值时会产生一个值foo 的 -2:
byte foo = (byte)((bar & ((byte)-64)) >>> 6);
这意味着获取一个 8 位字节,最左边 2 位的掩码,并将它们移到最右边的 2 位。 Ie:
initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b10000000
0b10000000 >>> 6 = 0b00000010
结果实际上是-2,也就是
0b11111110
Ie。 1 而不是零被移到左侧位置
Java has 2 bitshift operators for right shifts:
>> shifts right, and is dependant on the sign bit for the sign of the result
>>> shifts right and shifts a zero into leftmost bits
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/op3.html
This seems fairly simple, so can anyone explain to me why this code, when given a value of -128 for bar, produces a value of -2 for foo:
byte foo = (byte)((bar & ((byte)-64)) >>> 6);
What this is meant to do is take an 8bit byte, mask of the leftmost 2 bits, and shift them into the rightmost 2 bits. Ie:
initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b10000000
0b10000000 >>> 6 = 0b00000010
The result actually is -2, which is
0b11111110
Ie. 1s rather than zeros are shifted into left positions
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是因为 &实际上正在执行到
int
的提升 - 这留下了大量的“1”位。然后右移,将最左边的 2 位保留为 0,然后通过转换回字节来忽略这些最左边的位。当您分离出操作时,这一点会变得更清楚:
打印
So 再次进行位算术:
即使您从 & 中得到了正确的结果;操作(通过在该点进行转换),
>>>
无论如何都会首先将第一个操作数提升为int
。编辑:解决方案是改变掩盖事物的方式。不要用 -64 进行掩码,而只需用 128+64=192=0xc0 进行掩码:
这样,您实际上就只留下您想要的两位,而不是在最高有效 24 位中加载 1。
It's because the & is actually performing promotion to
int
- which leaves an awful lot of "1" bits. You're then shifting right, leaving the leftmost 2 bits as 0, but then ignoring those leftmost bits by casting back to byte.This becomes clearer when you separate out the operations:
prints
So to do your bit arithmetic again:
Even if you get the right result out of the & operation (by casting at that point),
>>>
will promote the first operand toint
first anyway.EDIT: The solution is to change how you mask things. Instead of masking by -64, mask by just 128+64=192=0xc0 instead:
That way you really only get left with the two bits you want, instead of having a load of 1s in the most significant 24 bits.
AFAIK,在 Java 中,大多数运算符(+、-、>>、& 等)无法处理小于 int 的任何值。因此,您的按位移位和
&
会在后台将值隐式转换为int
,然后通过外部显式转换返回byte
。最后一次转换消除了高位中的零。要获得您期望的结果,请尝试在
int
上执行此操作。AFAIK, in Java most operators (+,-,>>,& etc.) can't work on anything smaller than
int
s. So, your bitwise shifts and&
are implicitly casting the values intoint
in the background and then back intobyte
by your explicit cast outside. The last cast gets rid of the zeroes in the higher bits.To get results you would expect, try doing this on
int
s.其他人已经告诉你原因,但我将进一步分解并提供真正问题的答案。
自从 &运算符会将所有内容提升为 int,其作用本质上是:
如果 bar 为 -128,则 (int)bar 为 0xFFFFFF80,然后与 0xFFFFFFFC0 进行 & 运算...即:0xFFFFFF80,然后将其向右移动 6 个位置get: 0x3FFFFFFE
正确的答案非常简单:
将 bar 提升为 int 来表示 &操作,因此该 int 中剩下的唯一内容将是原始字节的前两位。然后将其右移 6 位并将其转换回字节。
Others have told you why but I'll break it down further and provide an answer to the real problem, too.
Since the & operator will promote everything to int, what this does is essentially:
If bar is -128 then (int)bar is 0xFFFFFF80 which is then &'ed with 0xFFFFFFC0... which is: 0xFFFFFF80, you then shift that right 6 places to get: 0x3FFFFFFE
The right answer is really simple:
bar is promoted to an int for the & operation so the only thing left in that int will be the top two bits of the original byte. Then shift it right 6 bits and convert it back to bytes.