Я хочу сохранить некоторые данные в байтовые массивы в Java. В основном только числа, которые могут занимать до 2 байтов на число.
Я хотел бы знать, как я могу преобразовать целое число в 2-байтовый массив байтов и наоборот. Я нашел множество решений, которые гуглили, но большинство из них не объясняют, что происходит в коде. Я много чего не понимаю, поэтому я был бы признателен за базовое объяснение.
java
types
endianness
Крис
источник
источник
Ответы:
Используйте классы найденные в
java.nio
пространстве имен, в частности,ByteBuffer
. Он может сделать всю работу за вас.источник
ByteBuffer
.wrap
иallocate
, они не возвращают экземпляр абстрактного классаByteBuffer
.Char
,Short
,Int
. Полагаю, я мог бы добавить 4 байта и каждый раз сбрасывать 4-й, но я бы предпочел этого не делать.При упаковке подписанных байтов в int каждый байт должен быть замаскирован, потому что он расширен до 32 бит (а не до нуля) из-за правила арифметического продвижения (описано в JLS, Conversions and Promotions).
Есть интересная головоломка, связанная с этим, описанная в Java Puzzlers («Большое наслаждение каждым байтом») Джошуа Блоха и Нила Гафтера. При сравнении значения байта со значением типа int байт расширяется до значения типа int, а затем это значение сравнивается с другим значением типа int.
Обратите внимание, что все числовые типы подписаны в Java, за исключением того, что char является 16-разрядным целочисленным типом без знака.
источник
& 0xFF
они не нужны.& 0xFF
s необходимы, так как он говорит JVM преобразовать подписанный байт в целое число только с этими установленными битами. В противном случае байт -1 (0xFF) превратится в int -1 (0xFFFFFFFF). Я могу ошибаться, и даже если это так, это не больно и проясняет ситуацию.byte b = 0; b |= 0x88; System.out.println(Integer.toString(b, 16)); //Output: -78 System.out.println(Integer.toString(b & 0xFF, 16)); //Output: 88
byte
с 0xFF (int
), JVM будет кастовалbyte
кint
с 1 расширенными или 0 расширенными согласовывая ведущим битый первым. В Java нет неподписанного байта ,byte
s всегда подписаны.ByteBuffer.getInt()
:,Reads the next four bytes at this buffer's current position
будут проанализированы только первые 4 байта, что не должно быть тем, что вы хотите.Вы также можете использовать BigInteger для байтов переменной длины. Вы можете преобразовать его в long, int или short, в зависимости от ваших потребностей.
или для обозначения полярности:
Чтобы вернуть байты просто:
источник
intValueExact
неintValue
Базовая реализация будет выглядеть примерно так:
Чтобы понять вещи, вы можете прочитать эту статью WP: http://en.wikipedia.org/wiki/Endianness
Приведенный выше исходный код будет выводиться
34 12 78 56 bc 9a
. Первые 2 байта (34 12
) представляют первое целое число и т. Д. Приведенный выше исходный код кодирует целые числа в формате с прямым порядком байтов.источник
источник
Кто-то с требованием, где он должен читать из битов, скажем, вы должны читать только из 3 битов, но вам нужно целое число со знаком, затем используйте следующее:
Магическое число
3
может быть заменено количеством используемых вами битов (не байтов) .источник
Как часто гуава имеет то, что вам нужно.
Чтобы перейти от байтового массива к int:, здесь
Ints.fromBytesArray
документЧтобы перейти от int к байтовому массиву:, здесь
Ints.toByteArray
документисточник
я думаю, что это лучший режим, чтобы привести к Int
первый преобразованный байт в строку
Следующим шагом является преобразование в Int
но байт находится в ярости от -128 до 127 для этого, я думаю, лучше использовать ярость от 0 до 255, и вам нужно только сделать это:
источник