Java's unsigned bitshift right (>>>) is signed shifting

Funtime60 :

I'm trying to bitshift right in order to isolate certain bits from a byte so I wanted an unsigned shift, the "new" bits should be zeros by my understanding. However, I've found that >>> has no difference to >> in my tests. -128 >> 4 = -8 as expected, but -128 >>> 4 should be 8 but I still get -8.

byte data = (byte)-128;
System.out.println((byte)(data >>> 4));
System.out.println((byte)(data >> 4));

Thanks for the help.

kaya3 :

The unsigned right-shift operator is indeed doing an unsigned right-shift in this code; it's just hidden because of implicit cast from byte to int. Says the Java Language Specification (§15.19):

The operators << (left shift), >> (signed right shift), and >>> (unsigned right shift) are called the shift operators. The left-hand operand of a shift operator is the value to be shifted; the right-hand operand specifies the shift distance. [...] Unary numeric promotion (§5.6.1) is performed on each operand separately.

Unary numeric promotion means (§5.6.1):

[...] if the operand is of compile-time type byte, short, or char, it is promoted to a value of type int by a widening primitive conversion (§5.1.2).

So your code is evaluated as follows:

  • The byte value -128 which is the left operand of >>> is promoted to the int value -128, which is 0b11111111111111111111111110000000 in binary.
  • The unsigned right-shift is done on this int value, with the result 268435448 which in binary is 0b00001111111111111111111111111000. Note that the four left-most bits are zero, as you would expect from an unsigned right-shift.
  • This result is then explicitly casted to (byte), giving the result -8.

Using the REPL:

> byte b = -128;
> int shifted = b >>> 4;
> shifted
268435448
> (byte) shifted
-8

For the behaviour you want, you can use & 0xFF to do an "unsigned" conversion from byte to int:

> ((b & 0xFF) >>> 4)
8

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=4359&siteId=1