Представление числа в байтовом массиве (Java-программирование) - PullRequest
6 голосов
/ 19 мая 2010

Я пытаюсь представить номер порта 9876 (или 0x2694 в шестнадцатеричном виде) в двухбайтовом массиве:

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

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

Но я получаю предупреждение о возможной потере точности:

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

Как я могу представить число 9876 в двухбайтовом массиве без потери точности?

ПРИМЕЧАНИЕ: Я выбрал код @ Björn как правильный ответ, но код @glowcoder также хорошо работает. Это просто другой подход к той же проблеме. Спасибо всем!

Ответы [ 7 ]

6 голосов
/ 19 мая 2010

Вы пробовали приводить к байту? например,

sendData[1] = (byte)0x94;
3 голосов
/ 20 мая 2010

Бьёрн дал хороший общий ответ с использованием потоков. Вы также можете сделать то же самое, используя java.nio.ByteBuffer, что приводит к немного меньшему количеству кода, а также вы можете контролировать порядок байтов в выходных данных.

Чтобы создать байтовый массив:

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

Чтобы изменить это:

public static int fromByteArray(byte[] b) {
    ByteBuffer buf = ByteBuffer.wrap(b);
    return buf.getInt();
}
3 голосов
/ 20 мая 2010

0x94 - это 148 в десятичном виде, что превышает диапазон байтов в java (от -128 до 127).Вы можете выполнить одно из следующих действий:

1) Приведение будет работать нормально, поскольку оно сохранит двоичное представление (никакие значащие биты не усекаются для 0x00 до 0xFF):

 sendData[1] = (byte)0x94; 

2) Двоичное представление 0x94 в виде подписанного байта равно -108 (-0x6C), поэтому следующее будет иметь тот же эффект:

sendData[1] = -0x6C; //or -108 in decimal
1 голос
/ 20 мая 2010

Моим первым ответом был бы сдвиг битов, но после второй мысли я думаю, что использование выходных потоков может быть лучше и проще для понимания. Я обычно избегаю кастинга, но если вы не собираетесь использовать общее решение, я думаю, это будет хорошо. :)

Использование потоков, общее решение:

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();
}

И чтобы изменить это:

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 голос
/ 19 мая 2010

Попробуйте это:

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

Или это:

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

Вы должны преобразовать данные в байт, чтобы назначить их байту!

То естьне означает, что вы потеряли точность, просто запись 0x26 означает преобразование int в Java ..

Но также обратите внимание: диапазон байтов составляет от -128 до 127, поэтому в случае 0x94=148 это будетпредставленный после преобразования байтов как -108, поэтому он не будет работать корректно в математических вычислениях.

1 голос
/ 19 мая 2010

Вы должны привести к (байту), так как тип числа по умолчанию в java - это int, который больше байта. Пока значение вписывается в байты, все в порядке.

0 голосов
/ 19 мая 2010

Это потому, что все в Java подписано. 0x94 (148) больше, чем Byte.MAX_VALUE (2 ^ 7-1).

Что вам нужно, это

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;
}
...