Java convert byte to float

Преобразование массива байтов в числовое представление в 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 .

Оцените статью