110

I need to convert a number into an unsigned byte. The number is always less than or equal to 255, and so it will fit in one byte.

I also need to convert that byte back into that number. How would I do that in Java? I've tried several ways and none work. Here's what I'm trying to do now:

int size = 5;
// Convert size int to binary
String sizeStr = Integer.toString(size);
byte binaryByte = Byte.valueOf(sizeStr);

and now to convert that byte back into the number:

Byte test = new Byte(binaryByte);
int msgSize = test.intValue();

Clearly, this does not work. For some reason, it always converts the number into 65. Any suggestions?

darksky
  • 20,411
  • 61
  • 165
  • 254
  • I also tried this method: http://www.crazysquirrel.com/computing/java/basics/how-to-convert-bytes.jspx - does not work. – darksky Sep 13 '11 at 12:05

12 Answers12

231

A byte is always signed in Java. You may get its unsigned value by binary-anding it with 0xFF, though:

int i = 234;
byte b = (byte) i;
System.out.println(b); // -22
int i2 = b & 0xFF;
System.out.println(i2); // 234
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • I'm still getting 65... Why is that? – darksky Sep 13 '11 at 12:15
  • You have a problem with your code. If you replace 234 by 5 in my code and run it, it will print 5 twice. – JB Nizet Sep 13 '11 at 12:18
  • Okay I get it.. So it is not actually storing the number I want in the byte. I will look into that. Could you check my edited question about strings conversion please? – darksky Sep 13 '11 at 12:21
  • 1
    It is storing the number you want in the byte. Java just considers it as a signed number rather than an unsigned one. But every bit is the same as if it was an unsigned number. Your string conversion into bytes is another, unrelated question. Post it separately, in a new question. – JB Nizet Sep 13 '11 at 12:24
  • What if I converted the number using a buffer array? Do I retrieve in the same way? I used the `putInt()` method in the buffer array. – darksky Sep 13 '11 at 15:04
  • 1
    use getInt to get back your int, and transform the int as a byte. An int is an int. Where it comes from doesn't matter. – JB Nizet Sep 13 '11 at 15:49
  • 1
    Java bytes are signed? Good lord, what horror. – Nyerguds Aug 26 '15 at 12:25
  • 24
    Why does bitwise and with `0xFF` result in a unsigned integer? Some explanation would be really helpful. – user462455 Feb 03 '16 at 23:53
  • 4
    Java 8 use the same method: public static int toUnsignedInt(byte x) { return ((int) x) & 0xff; } – Daniel De León May 18 '17 at 21:56
  • Well, because it's probably the fastest and simplest method out there. JIT might even compile it to a single zero-extension instruction, which never results in any pipeline stalls and supported by virtually any CPU. – weaknespase Oct 27 '18 at 11:30
65

Java 8 provides Byte.toUnsignedInt to convert byte to int by unsigned conversion. In Oracle's JDK this is simply implemented as return ((int) x) & 0xff; because HotSpot already understands how to optimize this pattern, but it could be intrinsified on other VMs. More importantly, no prior knowledge is needed to understand what a call to toUnsignedInt(foo) does.

In total, Java 8 provides methods to convert byte and short to unsigned int and long, and int to unsigned long. A method to convert byte to unsigned short was deliberately omitted because the JVM only provides arithmetic on int and long anyway.

To convert an int back to a byte, just use a cast: (byte)someInt. The resulting narrowing primitive conversion will discard all but the last 8 bits.

Jeffrey Bosboom
  • 13,313
  • 16
  • 79
  • 92
8

If you just need to convert an expected 8-bit value from a signed int to an unsigned value, you can use simple bit shifting:

int signed = -119;  // 11111111 11111111 11111111 10001001

/**
 * Use unsigned right shift operator to drop unset bits in positions 8-31
 */
int psuedoUnsigned = (signed << 24) >>> 24;  // 00000000 00000000 00000000 10001001 -> 137 base 10

/** 
 * Convert back to signed by using the sign-extension properties of the right shift operator
 */
int backToSigned = (psuedoUnsigned << 24) >> 24; // back to original bit pattern

http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

If using something other than int as the base type, you'll obviously need to adjust the shift amount: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

Also, bear in mind that you can't use byte type, doing so will result in a signed value as mentioned by other answerers. The smallest primitive type you could use to represent an 8-bit unsigned value would be a short.

dm78
  • 1,570
  • 1
  • 16
  • 28
6

Except char, every other numerical data type in Java are signed.

As said in a previous answer, you can get the unsigned value by performing an and operation with 0xFF. In this answer, I'm going to explain how it happens.

int i = 234;
byte b = (byte) i;
System.out.println(b);  // -22

int i2 = b & 0xFF;      
// This is like casting b to int and perform and operation with 0xFF

System.out.println(i2); // 234

If your machine is 32-bit, then the int data type needs 32-bits to store values. byte needs only 8-bits.

The int variable i is represented in the memory as follows (as a 32-bit integer).

0{24}11101010

Then the byte variable b is represented as:

11101010

As bytes are signed, this value represent -22. (Search for 2's complement to learn more about how to represent negative integers in memory)

Then if you cast is to int it will still be -22 because casting preserves the sign of a number.

1{24}11101010

The the casted 32-bit value of b perform and operation with 0xFF.

 1{24}11101010 & 0{24}11111111
=0{24}11101010

Then you get 234 as the answer.

Amish Bedi
  • 65
  • 1
  • 2
  • 9
Ramesh-X
  • 4,853
  • 6
  • 46
  • 67
  • Thank you. Still not sure how you get -22 from 234 please? – Avv Mar 24 '22 at 13:04
  • 1
    @Avv I believe you agree that if you cast `int 234` the resulting value's binary representation will be `11101010`, right? Also it is stored in the RAM as a `byte` type with these binary values. Then you need to learn how to represent a negative number in the system memory (ones complement & twos complement) and soon you will realize that the binary `11101010` is the representation of `-22`. – Ramesh-X Mar 25 '22 at 02:54
4

The solution works fine (thanks!), but if you want to avoid casting and leave the low level work to the JDK, you can use a DataOutputStream to write your int's and a DataInputStream to read them back in. They are automatically treated as unsigned bytes then:

For converting int's to binary bytes;

ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
int val = 250;
dos.write(byteVal);
...
dos.flush();

Reading them back in:

// important to use a (non-Unicode!) encoding like US_ASCII or ISO-8859-1,
// i.e., one that uses one byte per character
ByteArrayInputStream bis = new ByteArrayInputStream(
   bos.toString("ISO-8859-1").getBytes("ISO-8859-1"));
DataInputStream dis = new DataInputStream(bis);
int byteVal = dis.readUnsignedByte();

Esp. useful for handling binary data formats (e.g. flat message formats, etc.)

Gregor
  • 1,297
  • 1
  • 19
  • 31
3

The Integer.toString(size) call converts into the char representation of your integer, i.e. the char '5'. The ASCII representation of that character is the value 65.

You need to parse the string back to an integer value first, e.g. by using Integer.parseInt, to get back the original int value.

As a bottom line, for a signed/unsigned conversion, it is best to leave String out of the picture and use bit manipulation as @JB suggests.

Péter Török
  • 114,404
  • 31
  • 268
  • 329
  • So like this? (Still getting 65 here) `String sizeStr = Integer.toString(size); int sizeInt = Integer.parseInt(sizeStr); byte binaryByte = Byte.valueOf((byte) sizeInt);` – darksky Sep 13 '11 at 12:16
  • @Nayefc, I updated my answer just as you were writing your comment :-) – Péter Török Sep 13 '11 at 12:16
  • Alright thanks! For some reason it STILL prints out 65 though. What does this mean? If it just shows 65, what is actually being stored in the byte then I don't get it. Also please check my question, I edited it and added a section about the strings conversion :) – darksky Sep 13 '11 at 12:18
  • @Nayefc, again, `String.getBytes()` yields the ASCII values of the *characters* contained in the text, not the numeric values of digits. You need to *parse* the string into a numeric value, as I hinted above. – Péter Török Sep 13 '11 at 12:25
  • Oh here, I am trying to convert a string to bytes and back to a string. So I am trying to store "Hello" as byte and then retrieve it later as a string. – darksky Sep 13 '11 at 12:27
  • 1
    @Nayefc, so that is actually a whole different question. And AFAIS it should work. Create a new question, including the actual input and output of the conversion, and the full code to reproduce the case. – Péter Török Sep 13 '11 at 12:31
1

Even though it's too late, I'd like to give my input on this as it might clarify why the solution given by JB Nizet works. I stumbled upon this little problem working on a byte parser and to string conversion myself. When you copy from a bigger size integral type to a smaller size integral type as this java doc says this happens:

https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3 A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.

You can be sure that a byte is an integral type as this java doc says https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html byte: The byte data type is an 8-bit signed two's complement integer.

So in the case of casting an integer(32 bits) to a byte(8 bits), you just copy the last (least significant 8 bits) of that integer to the given byte variable.

int a = 128;
byte b = (byte)a; // Last 8 bits gets copied
System.out.println(b);  // -128

Second part of the story involves how Java unary and binary operators promote operands. https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2 Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:

If either operand is of type double, the other is converted to double.

Otherwise, if either operand is of type float, the other is converted to float.

Otherwise, if either operand is of type long, the other is converted to long.

Otherwise, both operands are converted to type int.

Rest assured, if you are working with integral type int and/or lower it'll be promoted to an int.

// byte b(0x80) gets promoted to int (0xFF80) by the & operator and then
// 0xFF80 & 0xFF (0xFF translates to 0x00FF) bitwise operation yields 
// 0x0080
a = b & 0xFF;
System.out.println(a); // 128

I scratched my head around this too :). There is a good answer for this here by rgettman. Bitwise operators in java only for integer and long?

KaziQ
  • 13
  • 3
0

In terms of readability, I favor Guava's:

  • UnsignedBytes.checkedCast(long) to convert a signed number to an unsigned byte.
  • UnsignedBytes.toInt(byte) to convert an unsigned byte to a signed int.
Gili
  • 86,244
  • 97
  • 390
  • 689
0

If you want to use the primitive wrapper classes, this will work, but all java types are signed by default.

public static void main(String[] args) {
    Integer i=5;
    Byte b = Byte.valueOf(i+""); //converts i to String and calls Byte.valueOf()
    System.out.println(b);
    System.out.println(Integer.valueOf(b));
}
Romeo
  • 337
  • 1
  • 6
  • 17
-1

Handling bytes and unsigned integers with BigInteger:

byte[] b = ...                    // your integer in big-endian
BigInteger ui = new BigInteger(b) // let BigInteger do the work
int i = ui.intValue()             // unsigned value assigned to i
pgrandjean
  • 676
  • 1
  • 9
  • 19
-1

in java 7

public class Main {
    public static void main(String[] args) {
        byte b =  -2;
        int i = 0 ;
        i = ( b & 0b1111_1111 ) ;
        System.err.println(i);
    }
}

result : 254

-1

I have tested it and understood it. In Java, the byte is signed, so 234 in one signed byte is -22, in binary, it is "11101010", signed bit has a "1", so with negative's presentation 2's complement, it becomes -22. And operate with 0xFF, cast 234 to 2 byte signed(32 bit), keep all bit unchanged.

I use String to solve this:

int a = 14206;
byte[] b = String.valueOf(a).getBytes();
String c = new String(b);
System.out.println(Integer.valueOf(c));

and output is 14206.

Yu Chai
  • 77
  • 4