1

I don't understand the output from the following code:

public static void main(String[] args) {
    int i1, i2, i3, i4;
    byte b;
    i1 = 128;
    b = (byte) i1;
    i2 = (int) b;
    i3 = 0 | b;
    i4 = 1 << 7;
    System.out.format("i1: %d   b: %d   i2: %d   i3: %d   i4: %d\n", i1, b, i2, i3, i4);
}

Output:

i1: 128   b: -128   i2: -128   i3: -128   i4: 128

Because byte is an 8-bit two's-complement signed integer, the binary representations with a 1 in the most significant bit are interpreted as negative values, which is why b becomes -128, which I'm totally fine with. I also understand that it's probably a good idea to keep the interpretation consistent when casting, as with i2. But shouldn't i3 and i4 have identical bit patterns and therefore map to identical int values?

Hanno Fietz
  • 30,799
  • 47
  • 148
  • 234
  • i would just like to express my indignation about Java's bytes. As I learned it, byte is by definition a number between 0 and 255 and therefore the complete mess they have done to byte in Java can not be excused. The -128..127 calls for a new primitive data type. – Peter Perháč Apr 21 '09 at 08:56
  • 1
    I would like to see that definition. The definitions I googled say that a byte is 8 bits, enough to represent a character. – Peter Lawrey Apr 21 '09 at 20:54
  • I guess I just got so used to the idea that the color components R G B are BYTES in range 0..255. Also the ASCII table maps characters to numbers in this range. I have never tried typing Alt+(-)+(number), it's always been a positive number 0..255. I was appalled by the conception of byte data type in Java. – Peter Perháč Apr 26 '09 at 15:43

7 Answers7

5

In this line:

i3 = 0 | b;

The "b" variable is automatically promoted to int type with sign extension because of the | operator, so becomes (int)-128, i.e. 0xffffff80.

When "or"ed with zero, its still the same value, namely -128

Alnitak
  • 334,560
  • 70
  • 407
  • 495
4

No, i4 is not a byte value, it's an int. That means that its sign bit is bit 31, not bit 7.

UPDATE: i3 is an int too, but it is initialized by extending a byte, so it keeps the sign from the byte value.

unwind
  • 391,730
  • 64
  • 469
  • 606
4

Sign extension is what is making i2 and i3 negative.

In the expression (0 | b), b is promoted to an int, and sign extension occurs as part of this promotion.

That's not happening in the expression assigned to i4. The constants 1 and 7 are already ints so there's no sign extension involved.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
2

i2 = (int) b;

i3 = 0 | b;

the i3 statement is equivalent to:

i3 = 0 | ((int) b) = 0 | i2 so naturally it is going to have the same value as i2

benmmurphy
  • 2,503
  • 1
  • 20
  • 30
1

In

i3 = 0 | b;

I'm guessing the 0 | b part is evaluated as a byte, and the results are then cast to an int, while in

i4 = 1 << 7;

the 1 << 7 part is already an int.

The above guess has been pointed out in the comments to be wrong!

The correct version is: In the top expression, the b is already cast to an int with sign extension before the OR operation.

Arjan Einbu
  • 13,543
  • 2
  • 56
  • 59
  • 1
    “0 | b” is _not_ evaluated as a byte. “b” is widened to int before the OR operation. – Bombe Apr 21 '09 at 09:19
1

That's simple. i3 = 0 | b; gets evaluated like byte, then it is converted to int. Whereas i4 = 1 << 7; will evaluate value as int and assign it to int. So in the first case we get 10000000b cast to int from byte, which will give us -128. And in the second we just assign this value to int without cast, which gives us 128.

dragonfly
  • 1,590
  • 10
  • 14
1

If you want to get the unsigned value of the bit pattern in a byte:

b & 0xff

See also this old answer.

Community
  • 1
  • 1
starblue
  • 55,348
  • 14
  • 97
  • 151