Я пытаюсь представить номер порта 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 также работает хорошо. Это - просто другой подход к той же проблеме. Спасибо всем!
Моим первым ответом был бы битовый сдвиг, но, подумав, я решил, что использование выходных потоков может быть лучше и проще для понимания. Я обычно избегаю кастинга, но если вы не собираетесь использовать универсальное решение, я думаю, это будет нормально. :)
Использование потоков, универсальное решение:
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();
}
Вы пробовали преобразование в байт? например
sendData[1] = (byte)0x94;
Бьорн дал хороший общий ответ с использованием потоков. Вы также можете сделать то же самое, используя 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();
}
0x94 - 148 в десятичной системе счисления, что превышает диапазон байтов в java (от -128 до 127). Вы можете сделать одно из следующего:
1) Приведение будет работать нормально, потому что оно сохранит двоичное представление (никакие значащие биты не усекаются от 0x00 до 0xFF):
sendData[1] = (byte)0x94;
2) Двоичное представление 0x94 как знаковое байт равен -108 (-0x6C), поэтому следующий результат будет иметь тот же эффект:
sendData[1] = -0x6C; //or -108 in decimal
Это потому, что все в 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;
}
Вы должны привести к (байту), поскольку тип числа по умолчанию в java - int, который больше байта. Пока значение умещается в байтах, его можно преобразовать.
Попробуйте следующее:
sendData[0] =(byte)0x26
sendData[1] =(byte)0x94
Или это:
sendData[0] =(byte)38
sendData[1] =(byte)148
Вы должны преобразовать данные в байт, чтобы назначить их байту!
Это не означает, что вы потеряли точность, просто написание 0x26
означает int для компилятора Java.
Но также обратите внимание: диапазон байтов от -128 до 127, поэтому в случае 0x94 = 148
он будет представлен после преобразования байтов как «-108», поэтому он не будет корректно работать в математических вычислениях ..