package com.example.foo; import static java.util.Arrays.asList; import java.io.InputStream; import java.io.OutputStream; /** *

* This demonstrates how to convert from int to byte and vice versa, if you want to ignore the sign. * The values then simply go from 0 to 255. *

* *

* This is needed when you want to process bytes that do not represent signed values. An example for * this is a stream of bytes that represent US-ASCII characters (8 bits per character). Java only * offers a type for 16 bit unsigned characters (UTF-16). *

* *

* The abstract class {@link OutputStream} also uses int to write. This is explained on the method * write: {@link java.io.OutputStream#write(int)}
* The same is true for reading bytes using {@link InputStream}.
* I wonder why they do not just use char instead of int. It would use less memory. Then again, it * doesn't really matter when you use single values or small buffers. *

* *

* Conversion rules are tricky. The specifications can be found here:
* JLS: Chapter 5. Conversions * and Promotions *

*

* Never cast from byte to int when you process binary data. That only makes sense if you want to * have the same value but not the same data. Negative values will remain negative, but the binary * representation is different.
* When processing the data you must not forget that Java still interprets the bytes as signed.
* Beware of operations that result in overflows. When using an int you can simply use * (i && 0xFF) to ignore the extra bits and then cast to byte. Note that * (i % 256) may result in a negative value and should not be used for binary data. *

*/ public class UnsignedBytesInJava { public static void main(final String[] args) { // Some bytes. You could also use binary or hex. final byte min = Byte.MIN_VALUE; // = 0b1000_0000 = 0x80 final byte negOne = -1;// = 0b1111_1111 = 0xFF final byte zero = 0;// = 0b0000_0000 = 0x00 final byte one = 1;// = 0b0000_0001 = 0x01 final byte max = Byte.MAX_VALUE; // = 0b0111_1111 = 0x7F // let's test all 5 values: for (final byte b : asList(min, negOne, zero, one, max)) { // So we can't just cast from byte to int because they are both signed. // Instead we use the binary pattern of 0xFF. // The & operator stands for "binary AND". final int asInt = byteToInt(b); // = b & 0xFF = b & 0b1111_1111 // Java always creates strings in decimal, signed representation. // The only exception is the type char, which is unsigned. // So we get different results for byte and int, but the bits are the same. System.out.println("byte value: " + b); System.out.println("as int: " + asInt); // Since the same bits are set we can convert byte to a byte. // In this case it's ok to just cast from int to byte. final byte b2 = intToByte(asInt); // = (byte) i System.out.println("byte again: " + b2); // same as above! if (b != b2) // let's check that. throw new RuntimeException("wrong value!"); // Now let's see if the bits really are the same. final String binaryStringByte = toBinaryString(b); System.out.println("binary byte: " + binaryStringByte); final String binaryStringInt = toBinaryString(asInt); System.out.println("binary int: " + binaryStringInt); // The word size is different (8 bits vs. 32 bits). // But the least significant bits are the same. // Let's check if this is true: if (!binaryStringInt.endsWith(binaryStringByte)) throw new RuntimeException("binary representation not correct!"); System.out.println("---------------------------"); } } /** * Converts a byte to an int so that the 8 least significant bits are unaltered. * * @see java.lang.Byte#toUnsignedInt(byte) */ private static int byteToInt(final byte b) { // return b & 0xFF; return Byte.toUnsignedInt(b); } /** * Converts a byte to an int to a byte. Values from 0 to 127 are the same, while values from 128 * to 255 get mapped from -128 to -1. No other integers should be passed to this method. The 8 * least significant bits are unaltered and the resulting value is interpreted as a signed bit. * * @throws IllegalArgumentException * When the value is not a byte (-128 to 127) * */ private static byte intToByte(final int i) throws IllegalArgumentException { if (i < 0 || i > 255) throw new IllegalArgumentException("Thats not a byte!"); return (byte) i; } // If you want the method to just ignore the 24 leading bits: // private static byte intToByte(final int i) { return (byte) (i & 0xFF); } /** * Converts value of byte to binary (ones and zeroes, eight in total). The returned string has the * most significant bit on the left. */ private static String toBinaryString(final byte b) { final StringBuilder result = new StringBuilder(); for (int x = 0; x < Byte.SIZE; x++) { final int p = 1 << x; if ((b & 0xFF & p) != 0) result.append('1'); else result.append('0'); if (x % 4 == 3) result.append(' '); } return result.reverse().toString().trim(); } /** * Converts value of int to binary (ones and zeroes, 32 in total). The returned string has the * most significant bit on the left. */ private static String toBinaryString(final int i) { final StringBuilder result = new StringBuilder(); for (int x = 0; x < Integer.SIZE; x++) { final int p = 1 << x; if ((i & p) != 0) result.append('1'); else result.append('0'); if (x % 4 == 3) result.append(' '); } return result.reverse().toString().trim(); } }