Friday, May 30, 2008

Comparing byte and int in Java

Yet another blog title of mine with "in Java" at the end :)

Anyway, one of the most confusing aspects of dealing with byte in Java was its actual value range. Based on some simple JUnit tests I made, I got the following output:

0 byte = 0 int
1 byte = 1 int
126 byte = 126 int
127 byte = 127 int
-128 byte = 128 int
-127 byte = 129 int
-2 byte = 254 int
-1 byte = 255 int

Interesting ....

From here we can deduce:
1) byte goes from 0 to 127 then -128 to -1
2) the range above actually corresponds to integer values of 0 to 127 then 128 to 255

Here is the JUnit test case which produced the above output. Note that Java does not allow byte values:
1) beyond or equal 128 and;
2) less or equal to -129
... which explains the remarked code portions below.


import static org.junit.Assert.*;
import org.junit.Test;

public class BaitTest {

@Test
public void printNegativeByte() {
byte baitValue;
int intValue;

baitValue = 0;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = 1;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = 126;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = 127;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

// baitValue = 128;
// intValue = baitValue & 0xFF;
// System.out.println(baitValue + " byte = " + intValue + " int");

// baitValue = -129;
// intValue = baitValue & 0xFF;
// System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = -128;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = -127;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = -2;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = -1;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");
}

}

How to properly print a hexadecimal byte array in Java

Here is a JUnit snippet of how to properly print a hexadecimal byte array in Java. The byte array may actually be an array of integers as well.


import static org.junit.Assert.*;
import org.junit.Test;

public class HeksTest {

@Test
public void printHex() {
byte[] bs = {
(byte)0xCA,
(byte)0x00,
(byte)0x00,
(byte)0x16,
(byte)0x04
};

int[] parameterArray = new int[5];
parameterArray[0] = bs[0];
parameterArray[1] = bs[1];
parameterArray[2] = bs[2];
parameterArray[3] = bs[3];
parameterArray[4] = bs[4];


StringBuffer sb = new StringBuffer();
String hexString = "";
for (int i = 0; i < 5; i++) {
hexString = Integer.toHexString(0xFF & parameterArray[i]).toUpperCase();
if (hexString.length() == 1) {
// i.e. if its "4" then print out as "04"
sb.append("0");
}
sb.append(hexString);
sb.append(" ");
}

int length = sb.length();
sb.setLength(length - 1);
hexString = sb.toString();

System.out.println("address (hex) = [" + hexString + "]");

assertTrue("CA 00 00 16 04".equals(hexString));

hexString = null;
}

}


Perhaps the most important line in the above code is the one shown below. Take note of the toHexString method used here. Also, the array element conversion uses 0xFF to ensure that negative values are converted properly.


hexString = Integer.toHexString(0xFF & parameterArray[i]).toUpperCase();

Convert byte array to integer in Java

The following JUnit test shows how to convert a byte array into a single integer in Java.


import static org.junit.Assert.*;
import org.junit.Test;

public class BaitTest {

@Test
public void printInt() {
byte[] bs = {
(byte)0x00,
(byte)0x00,
(byte)0x00,
(byte)0x16,
(byte)0x04
};

int address = (bs[0] << 32) | (bs[1] << 24) |
(bs[2] << 16) | (bs[3] << 8) | bs[4];

System.out.println("address (int) = [" + address + "]");
System.out.printf("address (hex) = [%X]\n", address);

assertTrue(5636 == address);
}
}


In the above, the line :

int address = (bs[0] << 32) | (bs[1] << 24) |
(bs[2] << 16) | (bs[3] << 8) | bs[4];

is where we convert the byte array to a single integer using the assumption that the most significant byte (i.e. MSB) is at index 0. Note that the bit shift values are incremented by multiples of 8 i.e. or 8*0, 8*1, 8*2, 8*3 and 8*4.

In Java 5 upwards, to print a decimal number as hexadecimal, use the "%X" modifier in "printf", as shown in this line from the above code :

System.out.printf("address (hex) = [%X]\n", address);


You'll see that the above will print out "1604" (i.e. 00 00 00 16 04) which is what the byte array looks like at the top of the code, i.e. :


byte[] bs = {
(byte)0x00,
(byte)0x00,
(byte)0x00,
(byte)0x16,
(byte)0x04
};