Reputation: 33
i'm really confused with, well it's best if I show my code first so here's what I got.
void dumpInt(int x) throws IOException {
if ( true ) {
//8388638
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
writer.writeByte(x&0xff);
writer.writeByte((x>>8)&0xff);
writer.writeByte((x >> 16) & 0xfff);
writer.writeByte((x>>24)&0xff);
outputStream.write(x & 0xff);
outputStream.write((x >> 8) & 0xff);
outputStream.write((x >> 16) & 0xff);
outputStream.write((x >> 24) & 0xff);
System.out.println((x >> 16) & 0xff);
if(x == 8388638){
String xz = "";
byte[]array = outputStream.toByteArray();
System.out.println(array[2]+" | " + (char)array[2]);
}
} else {
writer.writeInt(x);
}
}
this works fine but when I do dumpInt(8388638), I get some weird occurrences.
writer.writeByte((x >> 16) & 0xfff)
writes -128 to the writer
Im clueless as why that is.
The same thing happens for outputStream.write((x >> 16) & 0xff);
but when I run System.out.println((x >> 16) & 0xff);
it outputs 128(positive)
Does anybody know why this is and how I can correct it? (Sorry i'm somewhat experienced in java but im not the best by any means so if this is a really simple fix my bad)
Upvotes: 3
Views: 147
Reputation: 40034
The same thing happens for outputStream.write((x >> 16) & 0xff); but when I run System.out.println((x >> 16) & 0xff); it outputs 128(positive) Does anybody know why this is and how I can correct it?
int x = 8388638;
When you do the following:
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write((x >> 16) & 0xff);
System.out.println(outputStream.toByteArray()[0]);
You are printing a -128 because the value is 0b1000_0000
which is -128 in
two's complement form for a byte (the high order bit being the sign bit).
When you do this:
System.out.println((x >> 16) & 0xff);
(x>>16)
is still an int
and then the &
masks off the top 24 bits. So the low order 8 bits print as an int
and two's complement does not come into play.
For more information check out Two's Complement
Upvotes: 1
Reputation: 271105
Bytes in Java are signed, and have the range -128~127. You seem to be more familiar with the other decimal representation of a byte - the unsigned byte, having a range from 0 to 255. However, that doesn't exist in Java as a separate data type.
The following shows corresponding values between the two representations:
signed -128 -127 -126 ... -1 0 1 ... 126 127 128
unsigned 128 129 130 ... 255 0 1 ... 126 127 128
Note: these are not really different representations in binary. They have the same binary representation. It depends on whether you interpret the MSB as the sign bit or not.
You can convert from the signed version to the unsigned version by Byte.toUnsignedInt
, and you can convert from the unsigned version to the signed version by casting to byte
.
For some reason that you'd have to ask the API designers, OutputStream.write
accepts unsigned bytes (as well as signed ones). How does Java do this if byte
only ranges from -128 to 127? It accepts an int
rather than a byte
! This is the reason why your code compiles at all.
write
(which writeByte
also calls) converts the int
128 to a (signed) byte
-128 and writes it into the stream. When you get the written bytes later, you are getting the converted signed byte
. But in fact, in terms of the bits, 128 and -128 are the same 1000 0000
. It's just that Java insists on interpreting the first 1
as a sign bit.
As I said before, you can convert the -128
to 128` if you prefer the other representation:
Byte.toUnsignedInt(-128) // 128
Note that the result must be an int
, because the result is outside of byte
's range.
Upvotes: 1
Reputation: 102872
In java, a byte has the range of [-128, +127]
, as in, +128 is literally impossible. In fact, -128
is how a byte that holds +128 is printed (in the sense that +128 is, in bits, 1000 0000
, and as a java byte, as they are signed, that is rendered as -128, because that's also 1000 0000
.
In other words, your app is working fine.
Your linked picture in your comment is due to you misunderstanding how parentheses and operator priority works in java.
System.out.println((byte)(x>>16)&0xff);
resolves like so:
(byte)(x>>16)
&
0xFF
and as 0xFF
is an int (all numeric literals are always an int, unless they end in a capital L
, then they are a long. You can't put a byte or short literal in java code), that's an operation between a byte and an int, and like all ops between bytes and ints, this is resolved by first upgrading the byte to an int, and then returning the result by doing the op on the two resulting ints. In other words, it is this:
(int)((byte)(x>>16)
&
0xFF
And that'd be +128.
Try this:
(byte)((x>>16) & 0xFF)
. You'll find it prints -128
as expected.
Upvotes: 1