- Преобразование массива байтов в числовое представление в Java
- 2. Использование операторов сдвига
- 2.1. Byte Array to int и long
- 2.2. int и long в байтовый массив
- 2.3. Массив байтов для плавания и удвоения
- 2.4. float и double для массива байтов
- 3. Использование байтового буфера
- 3.1. Массив байтов в числовое значение
- 3.2. Использование существующего массива байтов
- 4. Использование BigInteger
- 4.1. Byte Array to int и long
- 4.2. Массив байтов для плавания и удвоения
- 5. Использование гуавы
- 5.1. Byte Array to int и long
- 5.2. Массив байтов для плавания и удвоения
- 6. Использование CommonsLang
- 6.1. Byte Array to int и long
- 6.2. Массив байтов для плавания и удвоения
- 7. Заключение
Преобразование массива байтов в числовое представление в Java
В этом руководстве мы рассмотрим различные подходы к преобразованию массива байтов в числовое значение ( int , long , float , double ) и наоборот.
Байт является основной единицей информации в компьютере для хранения и обработки. Примитивные типы, определенные в языке Java, представляют собой удобный способ манипулирования несколькими байтами одновременно. Следовательно, между массивом байтов и примитивными типами существует неотъемлемая связь преобразования .
Поскольку типы short и char состоят всего из двух байтов, они не требуют особого внимания. Итак, мы сосредоточимся на преобразовании между байтовым массивом и типами int , long , float и double .
2. Использование операторов сдвига
Самый простой способ преобразовать массив байтов в числовое значение — использовать операторы сдвига .
2.1. Byte Array to int и long
При преобразовании массива байтов в значение int мы используем оператор
int value = 0; for (byte b : bytes) value = (value <8) + (b & 0xFF); >
Обычно длина массива байтов в приведенном выше фрагменте кода должна быть равна или меньше четырех. Это потому, что значение int занимает четыре байта. В противном случае это приведет к переполнению диапазона int .
Для проверки правильности преобразования определим две константы:
byte[] INT_BYTE_ARRAY = new byte[] (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE >; int INT_VALUE = 0xCAFEBABE;
Если мы внимательно посмотрим на эти две константы, INT_BYTE_ARRAY и INT_VALUE , мы обнаружим, что они представляют собой разные представления шестнадцатеричного числа 0xCAFEBABE .
Затем давайте проверим правильность этого преобразования:
int value = convertByteArrayToIntUsingShiftOperator(INT_BYTE_ARRAY); assertEquals(INT_VALUE, value);
Точно так же при преобразовании массива байтов в длинное значение мы можем повторно использовать приведенный выше фрагмент кода с двумя изменениями: тип значения — long , а длина байтов должна быть равна или меньше восьми.
2.2. int и long в байтовый массив
При преобразовании значения int в массив байтов мы можем использовать оператор >> (знаковый сдвиг вправо) или >>> (беззнаковый сдвиг вправо):
byte[] bytes = new byte[Integer.BYTES]; int length = bytes.length; for (int i = 0; i length; i++) bytes[length - i - 1] = (byte) (value & 0xFF); value >>= 8; >
В приведенном выше фрагменте кода мы можем заменить оператор >> на оператор >>> . Это потому, что мы используем только те байты, которые изначально содержит параметр value . Таким образом, сдвиг вправо с расширением знака или расширением нуля не повлияет на конечный результат.
Затем мы можем проверить правильность приведенного выше преобразования:
byte[] bytes = convertIntToByteArrayUsingShiftOperator(INT_VALUE); assertArrayEquals(INT_BYTE_ARRAY, bytes);
При преобразовании длинного значения в массив байтов нам нужно только изменить Integer.BYTES на Long.BYTES и убедиться, что тип значения — long .
2.3. Массив байтов для плавания и удвоения
При преобразовании массива байтов в число с плавающей запятой мы используем метод Float.intBitsToFloat () :
// convert bytes to int int intValue = 0; for (byte b : bytes) intValue = (intValue <8) + (b & 0xFF); > // convert int to float float value = Float.intBitsToFloat(intValue);
Из приведенного выше фрагмента кода мы можем узнать, что массив байтов нельзя преобразовать напрямую в значение с плавающей запятой . По сути, это занимает два отдельных шага: во-первых, мы переходим от массива байтов к значению int , а затем интерпретируем тот же битовый шаблон в значение с плавающей запятой .
Для проверки правильности преобразования определим две константы:
byte[] FLOAT_BYTE_ARRAY = new byte[] (byte) 0x40, (byte) 0x48, (byte) 0xF5, (byte) 0xC3 >; float FLOAT_VALUE = 3.14F;
Затем давайте проверим правильность этого преобразования:
float value = convertByteArrayToFloatUsingShiftOperator(FLOAT_BYTE_ARRAY); assertEquals(Float.floatToIntBits(FLOAT_VALUE), Float.floatToIntBits(value));
Точно так же мы можем использовать промежуточное длинное значение и метод Double.longBitsToDouble() для преобразования массива байтов в двойное значение .
2.4. float и double для массива байтов
При преобразовании числа с плавающей запятой в массив байтов мы можем воспользоваться методом Float.floatToIntBits() :
// convert float to int int intValue = Float.floatToIntBits(value); // convert int to bytes byte[] bytes = new byte[Float.BYTES]; int length = bytes.length; for (int i = 0; i length; i++) bytes[length - i - 1] = (byte) (intValue & 0xFF); intValue >>= 8; >
Затем давайте проверим правильность этого преобразования:
byte[] bytes = convertFloatToByteArrayUsingShiftOperator(FLOAT_VALUE); assertArrayEquals(FLOAT_BYTE_ARRAY, bytes);
По аналогии мы можем использовать метод Double.doubleToLongBits() для преобразования значения типа double в массив байтов . **
3. Использование байтового буфера
Класс java.nio.ByteBuffer предоставляет аккуратный унифицированный способ перевода между массивом байтов и числовым значением ( int , long , float , double ).
3.1. Массив байтов в числовое значение
Теперь мы используем класс ByteBuffer для преобразования массива байтов в значение типа int :
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES); buffer.put(bytes); buffer.rewind(); int value = buffer.getInt();
Затем мы используем класс ByteBuffer для преобразования значения int в массив байтов :
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES); buffer.putInt(value); buffer.rewind(); byte[] bytes = buffer.array();
Следует отметить, что приведенные выше два фрагмента кода следуют одному и тому же шаблону:
- Во-первых, мы используем метод ByteBuffer.allocate(int) для получения объекта ByteBuffer с указанной емкостью.
- Затем мы помещаем исходное значение ( массив байтов или значение int ) в объект ByteBuffer , например методы buffer.put(bytes) и buffer.putInt(value) .
- После этого мы сбрасываем позицию объекта ByteBuffer на ноль, чтобы мы могли читать с самого начала.
- Наконец, мы получаем целевое значение из объекта ByteBuffer , используя такие методы, как buffer.getInt() и buffer.array() .
Этот шаблон очень универсален и поддерживает преобразование типов long , float и double . Единственная модификация, которую нам нужно сделать, — это информация, относящаяся к типу.
3.2. Использование существующего массива байтов
Кроме того, метод ByteBuffer.wrap(byte[]) позволяет нам повторно использовать существующий массив байтов без создания нового:
ByteBuffer.wrap(bytes).getFloat();
Однако мы также должны отметить, что длина указанной выше переменной bytes равна или превышает размер целевого типа ( Float.BYTES ). В противном случае будет выброшено BufferUnderflowException .
4. Использование BigInteger
Основная цель класса java.math.BigInteger — представлять большие числовые значения, которые в противном случае не поместились бы в примитивный тип данных. Несмотря на то, что мы можем использовать его для преобразования между массивом байтов и примитивным значением, использование BigInteger немного тяжело для таких целей.
4.1. Byte Array to int и long
Теперь воспользуемся классом BigInteger для преобразования массива байтов в значение типа int :
int value = new BigInteger(bytes).intValue();
Точно так же класс BigInteger имеет метод longValue() для преобразования массива байтов в длинное значение:
long value = new BigInteger(bytes).longValue();
Кроме того, класс BigInteger также имеет метод intValueExact() и метод longValueExact() . Эти два метода следует использовать осторожно : если объект BigInteger выходит за пределы диапазона типа int или long , соответственно, оба метода вызовут исключение ArithmeticException .
При преобразовании значения int или long в массив байтов мы можем использовать один и тот же фрагмент кода:
byte[] bytes = BigInteger.valueOf(value).toByteArray();
Однако метод toByteArray () класса BigInteger возвращает минимальное количество байтов, не обязательно четыре или восемь байтов.
4.2. Массив байтов для плавания и удвоения
Хотя класс BigInteger имеет метод floatValue() , мы не можем использовать его для преобразования массива байтов в значение с плавающей запятой , как ожидалось. Так что нам делать? Мы можем использовать значение int в качестве промежуточного шага для преобразования массива байтов в значение с плавающей запятой :
int intValue = new BigInteger(bytes).intValue(); float value = Float.intBitsToFloat(intValue);
Точно так же мы можем преобразовать значение с плавающей запятой в массив байтов :
int intValue = Float.floatToIntBits(value); byte[] bytes = BigInteger.valueOf(intValue).toByteArray();
Аналогичным образом, воспользовавшись преимуществами методов Double.longBitsToDouble() и Double.doubleToLongBits() , мы можем использовать класс BigInteger для преобразования между массивом байтов и двойным значением.
5. Использование гуавы
Библиотека Guava предоставляет нам удобные методы для такого преобразования.
5.1. Byte Array to int и long
В Guava класс Ints в пакете com.google.common.primitives содержит метод fromByteArray() . Следовательно, нам довольно легко преобразовать массив байтов в значение int :
int value = Ints.fromByteArray(bytes);
Класс Ints также имеет метод toByteArray() , который можно использовать для преобразования значения int в массив байтов :
byte[] bytes = Ints.toByteArray(value);
И класс Longs похож в использовании на класс Ints :
long value = Longs.fromByteArray(bytes); byte[] bytes = Longs.toByteArray(value);
Кроме того, если мы проверим исходный код методов fromByteArray() и toByteArray() , то обнаружим, что оба метода используют операторы сдвига для выполнения своих задач .
5.2. Массив байтов для плавания и удвоения
В том же пакете также существуют классы Floats и Doubles . Но ни один из этих двух классов не поддерживает методы fromByteArray() и toByteArray() .
Однако мы можем использовать методы Float.intBitsToFloat() , Float.floatToIntBits() , Double.longBitsToDouble() и Double.doubleToLongBits() для завершения преобразования между массивом байтов и значением с плавающей запятой или двойным значением. Для краткости мы опустили здесь код.
6. Использование CommonsLang
Когда мы используем Apache Commons Lang 3 , выполнять такие преобразования немного сложно. Это связано с тем, что библиотека Commons Lang по умолчанию использует массивы байтов с прямым порядком байтов . Однако все массивы байтов , о которых мы упоминали выше, имеют порядок байтов с обратным порядком байтов. Таким образом, нам нужно преобразовать массив байтов с прямым порядком байтов в массив байтов с прямым порядком байтов и наоборот.
6.1. Byte Array to int и long
Класс Conversion в пакете org.apache.commons.lang3 предоставляет методы byteArrayToInt() и intToByteArray() .
Теперь давайте преобразуем массив байтов в значение int :
byte[] copyBytes = Arrays.copyOf(bytes, bytes.length); ArrayUtils.reverse(copyBytes); int value = Conversion.byteArrayToInt(copyBytes, 0, 0, 0, copyBytes.length);
В приведенном выше коде мы делаем копию исходной переменной bytes . Это связано с тем, что иногда мы не хотим изменять содержимое исходного массива байтов .
Затем давайте преобразуем значение int в массив байтов :
byte[] bytes = new byte[Integer.BYTES]; Conversion.intToByteArray(value, 0, bytes, 0, bytes.length); ArrayUtils.reverse(bytes);
Класс Conversion также определяет методы byteArrayToLong() и longToByteArray() . И мы можем использовать эти два метода для преобразования массива байтов в длинное значение.
6.2. Массив байтов для плавания и удвоения
Однако класс Conversion не предоставляет напрямую соответствующие методы для преобразования значения с плавающей запятой или двойного числа .
Опять же, нам нужно промежуточное целочисленное или длинное значение для преобразования между массивом байтов и значением с плавающей запятой или двойным значением.
7. Заключение
В этой статье мы проиллюстрировали различные способы преобразования массива байтов в числовое значение, используя простую Java с помощью операторов сдвига, ByteBuffer и BigInteger . Затем мы увидели соответствующие преобразования с использованием Guava и Apache Commons Lang.
Как обычно, исходный код этого руководства можно найти на GitHub .
- 1. Обзор
- 2. Использование операторов сдвига
- 2.1. Byte Array to int и long
- 2.2. int и long в байтовый массив
- 2.3. Массив байтов для плавания и удвоения
- 2.4. float и double для массива байтов
- 3.1. Массив байтов в числовое значение
- 3.2. Использование существующего массива байтов
- 4.1. Byte Array to int и long
- 4.2. Массив байтов для плавания и удвоения
- 5.1. Byte Array to int и long
- 5.2. Массив байтов для плавания и удвоения
- 6.1. Byte Array to int и long
- 6.2. Массив байтов для плавания и удвоения