Java bitshift strangeness

我只是一个虾纸丫 提交于 2019-12-05 09:44:57

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:

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);
    }
}

prints

67108862
-2

So to do your bit arithmetic again:

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

Even if you get the right result out of the & operation (by casting at that point), >>> will promote the first operand to int 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:

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

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, in Java most operators (+,-,>>,& etc.) can't work on anything smaller than ints. So, your bitwise shifts and & are implicitly casting the values into int in the background and then back into byte 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 ints.

Others have told you why but I'll break it down further and provide an answer to the real problem, too.

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

Since the & operator will promote everything to int, what this does is essentially:

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

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:

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

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!