6

I'm trying to represent the port number 9876 (or 0x2694 in hex) in a two byte array:

class foo {
     public static void main (String args[]) {
   byte[] sendData = new byte[1];

   sendData[0] = 0x26;
   sendData[1] = 0x94;
     }
}

But I get a warning about possible loss of precision:

foo.java:5: possible loss of precision
found   : int
required: byte
   sendData[1] = 0x94;
                 ^
1 error

How can I represent the number 9876 in a two byte array without losing precision?

NOTE: I selected the code by @Björn as the correct answer, but the code by @glowcoder also works well. It's just a different approach to the same problem. Thank you all!

2
  • 4
    Note that flattening data structures for sending over the wire is usually done with a DataOutputStream (or its subclass ObjectOutputStream) in Java. No need to reinvent the bitfiddling every time :-) Commented May 19, 2010 at 20:02
  • 1
    @meriton: and better yet, use java.nio.ByteBuffer which can do all this, not have to deal with IOException, and control endianness too. Commented May 20, 2010 at 3:27

7 Answers 7

6

Have you tried casting to a byte ? e.g.

sendData[1] = (byte)0x94;
Sign up to request clarification or add additional context in comments.

6 Comments

That will cause me to loose precision, won't it?
@Mark: It will make it clear to the compiler that you're doing exactly what you want to do. 0x94 is within the range of a byte, so there's no actual loss of precision here.
I thought the range of a byte was from -128 to 127, and 0x94 is 148
@Mark - 0x94 as a byte is not actually 148, it's -108.
@Mark: Well... no. Looking at the bits, the range of a byte is 0b00000000 to 0b11111111, and 0x94=0b10010100, which is properly in its range. Bitwise, the concept "signed byte" doesn't make any sense. It's only when you interpret a sequence of eight bits as an integer that it starts being clear.
|
3

0x94 is 148 in decimal, which exceeds the range of byte in java (-128 to 127). You can do one of the following:

1) A cast will work fine because it will preserve the binary representation (no meaningful bits are truncated for 0x00 to 0xFF):

 sendData[1] = (byte)0x94; 

2) The binary representation of 0x94 as a signed byte is -108 (-0x6C), so the following will have the same effect:

sendData[1] = -0x6C; //or -108 in decimal

1 Comment

And to convert the signed byte back to its unsigned int form, you can simply write b & 0xff.
3

Björn gave a good generic answer with using streams. You can also do this same thing using java.nio.ByteBuffer which results in slightly less code and you could also control endianess (byte order) of the output.

To create the byte array:

public static byte[] toByteArray(int bits) {
    ByteBuffer buf = ByteBuffer.allocate(4);
    buf.putInt(bits);
    return buf.array();
}

To reverse it:

public static int fromByteArray(byte[] b) {
    ByteBuffer buf = ByteBuffer.wrap(b);
    return buf.getInt();
}

Comments

1

My first answer would be bitshifting, but on a second thought I think using outputstreams could be better and more simple to understand. I usually avoid casting, but if you're not going for a generic solution I guess that would be okay. :)

Using streams, a generic solution:

public byte[] intToByteArray(final int i) throws java.io.IOException {
    java.io.ByteArrayOutputStream b = new java.io.ByteArrayOutputStream();
    java.io.DataOutputStream d = new java.io.DataOutputStream(b);
    d.writeInt(i);
    d.flush();

    return b.toByteArray();
}

And to reverse it:

public int byteArrayToInt(final byte[] b) throws IOException {
    java.io.ByteArrayInputStream ba = new java.io.ByteArrayInputStream(b);
    java.io.DataInputStream d = new java.io.DataInputStream(ba);

    return d.readInt();
}

1 Comment

You can also do this generically with java.nio.ByteBuffer and also control endianess if necessary. I've added an answer for this possibility.
1

You have to cast to (byte) as default number type in java is int, which is bigger than byte. As long as the value fits in byte it is ok to cast.

Comments

1

Try this:

sendData[0] =(byte)0x26
sendData[1] =(byte)0x94

Or this:

sendData[0] =(byte)38
sendData[1] =(byte)148

You must cast data into byte in order to assign it to a byte!

That does not mean you lost precision, just writing 0x26 means an int to Java compiler..

But also note: range of a byte is from -128 to 127, so in case of 0x94=148 it will be represented after byte casting as '-108' , so it will not work correctly in mathematical computations..

Comments

0

It's because everything in Java is signed. 0x94 (148) is greater than Byte.MAX_VALUE(2^7-1).

What you need is

public static byte[] intToByteArray(int value) {
    byte[] b = new byte[4];
    for (int i = 0; i < 4; i++) {
        int offset = (b.length - 1 - i) * 8;
        b[i] = (byte) ((value >>> offset) & 0xFF);
    }
    return b;
}

4 Comments

Note, this does all 4 bytes of the int... you only need two of them. The rest is straightforward from this.
that's two wrong--it's not because everything's signed, it's because 0x94 is an int, not a byte, and secondly the char type is unsigned, and thirdly--is that code a joke? If you're just messing with the guy it might be worth a +1 :) the original was fine if you downcast with (byte)
0x94 is an int because it doesn't fit into a byte because bytes are signed. You're correct that chars are unsigned - however, it's the exception to the rule because it's not intended to be a number - the JavaGods decided all their numbers will be signed. Can you use it like a number for String optimization? Yes you can. Was it intended to be used as number? No. Does the Character class extend the Number class? No. Third, no this code is not a joke, it's a legit way to convert any int to a byte array to accurately represent its bits. I've used it for TCP/IP packet creation in the past.
I tried your code, and it works great. Thank you for helping a beginner to learn Java!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.