Это потому, что & на самом деле выполняет повышение до 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);
Таким образом, вы действительно останетесь только с двумя битами, которые вам нужны, вместо того, чтобы иметь нагрузку 1 с в старших 24 битах.