Java bithift陌生

时间:2010-01-31 20:36:12

标签: java debugging bit-shift

Java有两个用于右移的位移操作符:

>> 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位。即:

initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b10000000
0b10000000 >>> 6 = 0b00000010

结果实际上是-2,即

0b11111110

IE中。 1而不是零被移动到左侧位置

3 个答案:

答案 0 :(得分:8)

这是因为&实际上正在向int执行促销 - 这留下了大量的“1”位。然后你向右移动,将最左边的2位保留为0,然后通过转回字节忽略那些最左边的位。

当您将操作分开时,这会变得更加清晰:

public class Test
{
    public static void main(String[] args)
    {
        byte bar = -128;
        int tmp = (bar & ((byte)-64)) >>> 6;
        byte foo = (byte)tmp;
        System.out.println(tmp);
        System.out.println(foo);
    }
}

打印

67108862
-2

所以再次进行比特运算:

initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b11111111111111111111111110000000 // it's an int now
0b10000000 >>> 6 = 0b00111111111111111111111111100000 // note zero-padding
(byte) (0b10000000 >>> 6) = 11100000 // -2

即使你从&中获得了正确的结果。操作(通过当时的转换),>>>将首先将第一个操作数提升为int

编辑:解决方案是改变你掩饰事物的方式。而不是通过-64屏蔽,而是仅通过128 + 64 = 192 = 0xc0掩码:

byte foo = (byte)((bar & 0xc0) >>> 6);

这样你真的只剩下你想要的两个位,而不是在最重要的24位中加载1s。

答案 1 :(得分:2)

AFAIK,在Java中,大多数运算符(+, - ,>>,&等)不能在小于int的任何小的情况下工作。因此,您的按位移位&会隐式地将值转换为背景中的int,然后通过外部显式转换返回byte。最后一次演员摆脱了较高位的零。

要获得您期望的结果,请尝试在int上执行此操作。

答案 2 :(得分:2)

其他人告诉你为什么,但我会进一步分解并提供真正问题的答案。

byte foo = (byte)((bar & ((byte)-64)) >>> 6);

自&运营商将把所有东西都推广到int,这本质上是做什么的:

byte foo = (byte)(((int)bar & (int)((byte)-64)) >>> 6);

如果bar是-128那么(int)bar是0xFFFFFF80然后用0xFFFFFFC0编辑...这是:0xFFFFFF80,然后你向右移动6位得到:0x3FFFFFFE

正确答案非常简单:

byte foo = (byte)((bar & 0xC0) >> 6);

栏被提升为&的一个int。操作因此int中唯一剩下的就是原始字节的前两位。然后将其右移6位并将其转换回字节。