Java shifts right to output negative values
I’m really confused, I’d better show my code first, that’s what I get.
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 great, but when I do dumpInt(8388638) I run into something weird.
writer.writeByte((x >> 16) & 0xfff)
writes -128 to writer
I don’t know why this is happening.
The same thing happens with outputStream.write(x >> 16) & 0xff);
But when I run System.out.println((x >> 16) & 0xff );
Output 128 (positive).
Does anyone know why this is and how I can correct it?
(Sorry, I have a bit of experience with Java, but I’m not the best anyway, so if this is a very simple fix my bug)
Solution
Bytes in Java are signed in the range -128~127. You seem to be more familiar with another decimal representation of bytes – unsigned bytes, ranging from 0 to 255. However, it does not exist as a separate data type in Java.
The following are the corresponding values for 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 binary representations. They have the same binary representation. This depends on whether you interpret the MSB as a sign bit.
You can convert
from a signed version to an unsigned version by Byte.toUnsignedInt
, and you can convert to a signed version by converting to byte
.
For some reasons why you must ask the API designer, OutputStream.write
accepts unsigned bytes (as well as signed bytes). If byte
has a range of -128 to 127, how can Java do that? It accepts ints
instead of byte
!
write (
writeByte
is also called) converts int
128 to (signed) byte
-128 and writes it to the stream. When you get the bytes written later, you will get the converted signed byte
. But in reality, in terms of 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 earlier, you can convert -128 to 128
‘: if you prefer other representations
Byte.toUnsignedInt(-128) // 128
Note that the result must be int
because the result is outside the scope of byte
.