Advertisement
DulcetAirman

Unsigned Bytes in Java

Dec 23rd, 2013
150
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package com.example.foo;
  2.  
  3. import static java.util.Arrays.asList;
  4.  
  5. import java.io.InputStream;
  6. import java.io.OutputStream;
  7.  
  8. /**
  9.  * <p>
  10.  * This demonstrates how to convert from int to byte and vice versa, if you want to ignore the sign.
  11.  * The values then simply go from 0 to 255.
  12.  * </p>
  13.  *
  14.  * <p>
  15.  * This is needed when you want to process bytes that do not represent signed values. An example for
  16.  * this is a stream of bytes that represent US-ASCII characters (8 bits per character). Java only
  17.  * offers a type for 16 bit unsigned characters (UTF-16).
  18.  * </p>
  19.  *
  20.  * <p>
  21.  * The abstract class {@link OutputStream} also uses int to write. This is explained on the method
  22.  * write: {@link java.io.OutputStream#write(int)}<br/>
  23.  * The same is true for reading bytes using {@link InputStream}.<br/>
  24.  * I wonder why they do not just use char instead of int. It would use less memory. Then again, it
  25.  * doesn't really matter when you use single values or small buffers.
  26.  * </p>
  27.  *
  28.  * <p>
  29.  * Conversion rules are tricky. The specifications can be found here: <br/>
  30.  * <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html">JLS: Chapter 5. Conversions
  31.  * and Promotions</a>
  32.  * </p>
  33.  * <p>
  34.  * Never cast from byte to int when you process binary data. That only makes sense if you want to
  35.  * have the same value but not the same data. Negative values will remain negative, but the binary
  36.  * representation is different. <br/>
  37.  * When processing the data you must not forget that Java still interprets the bytes as signed.<br/>
  38.  * Beware of operations that result in overflows. When using an int you can simply use
  39.  * <code>(i && 0xFF)</code> to ignore the extra bits and then cast to byte. Note that
  40.  * <code>(i % 256)</code> may result in a negative value and should not be used for binary data.
  41.  * </p>
  42.  */
  43. public class UnsignedBytesInJava {
  44.  
  45.   public static void main(final String[] args) {
  46.     // Some bytes. You could also use binary or hex.
  47.     final byte min = Byte.MIN_VALUE; // = 0b1000_0000 = 0x80
  48.     final byte negOne = -1;// = 0b1111_1111 = 0xFF
  49.     final byte zero = 0;// = 0b0000_0000 = 0x00
  50.     final byte one = 1;// = 0b0000_0001 = 0x01
  51.     final byte max = Byte.MAX_VALUE; // = 0b0111_1111 = 0x7F
  52.  
  53.     // let's test all 5 values:
  54.     for (final byte b : asList(min, negOne, zero, one, max)) {
  55.       // So we can't just cast from byte to int because they are both signed.
  56.       // Instead we use the binary pattern of 0xFF.
  57.       // The & operator stands for "binary AND".
  58.       final int asInt = byteToInt(b); // = b & 0xFF = b & 0b1111_1111
  59.       // Java always creates strings in decimal, signed representation.
  60.       // The only exception is the type char, which is unsigned.
  61.       // So we get different results for byte and int, but the bits are the same.
  62.       System.out.println("byte value: " + b);
  63.       System.out.println("as int: " + asInt);
  64.       // Since the same bits are set we can convert byte to a byte.
  65.       // In this case it's ok to just cast from int to byte.
  66.       final byte b2 = intToByte(asInt); // = (byte) i
  67.       System.out.println("byte again: " + b2); // same as above!
  68.       if (b != b2) // let's check that.
  69.         throw new RuntimeException("wrong value!");
  70.       // Now let's see if the bits really are the same.
  71.       final String binaryStringByte = toBinaryString(b);
  72.       System.out.println("binary byte: " + binaryStringByte);
  73.       final String binaryStringInt = toBinaryString(asInt);
  74.       System.out.println("binary int: " + binaryStringInt);
  75.       // The word size is different (8 bits vs. 32 bits).
  76.       // But the least significant bits are the same.
  77.       // Let's check if this is true:
  78.       if (!binaryStringInt.endsWith(binaryStringByte))
  79.         throw new RuntimeException("binary representation not correct!");
  80.       System.out.println("---------------------------");
  81.     }
  82.   }
  83.  
  84.   /**
  85.    * Converts a byte to an int so that the 8 least significant bits are unaltered.
  86.    *
  87.    * @see java.lang.Byte#toUnsignedInt(byte)
  88.    */
  89.   private static int byteToInt(final byte b) {
  90.     // return b & 0xFF;
  91.     return Byte.toUnsignedInt(b);
  92.   }
  93.  
  94.   /**
  95.    * Converts a byte to an int to a byte. Values from 0 to 127 are the same, while values from 128
  96.    * to 255 get mapped from -128 to -1. No other integers should be passed to this method. The 8
  97.    * least significant bits are unaltered and the resulting value is interpreted as a signed bit.
  98.    *
  99.    * @throws IllegalArgumentException
  100.    *           When the value is not a byte (-128 to 127)
  101.    * */
  102.   private static byte intToByte(final int i) throws IllegalArgumentException {
  103.     if (i < 0 || i > 255)
  104.       throw new IllegalArgumentException("Thats not a byte!");
  105.     return (byte) i;
  106.   }
  107.  
  108.   // If you want the method to just ignore the 24 leading bits:
  109.   // private static byte intToByte(final int i) { return (byte) (i & 0xFF); }
  110.  
  111.   /**
  112.    * Converts value of byte to binary (ones and zeroes, eight in total). The returned string has the
  113.    * most significant bit on the left.
  114.    */
  115.   private static String toBinaryString(final byte b) {
  116.     final StringBuilder result = new StringBuilder();
  117.     for (int x = 0; x < Byte.SIZE; x++) {
  118.       final int p = 1 << x;
  119.       if ((b & 0xFF & p) != 0)
  120.         result.append('1');
  121.       else
  122.         result.append('0');
  123.       if (x % 4 == 3)
  124.         result.append(' ');
  125.     }
  126.     return result.reverse().toString().trim();
  127.   }
  128.  
  129.   /**
  130.    * Converts value of int to binary (ones and zeroes, 32 in total). The returned string has the
  131.    * most significant bit on the left.
  132.    */
  133.   private static String toBinaryString(final int i) {
  134.     final StringBuilder result = new StringBuilder();
  135.     for (int x = 0; x < Integer.SIZE; x++) {
  136.       final int p = 1 << x;
  137.       if ((i & p) != 0)
  138.         result.append('1');
  139.       else
  140.         result.append('0');
  141.       if (x % 4 == 3)
  142.         result.append(' ');
  143.     }
  144.     return result.reverse().toString().trim();
  145.   }
  146. }
Advertisement
Advertisement
Advertisement
RAW Paste Data Copied
Advertisement