1. Overview
1.概述
In this tutorial, we’ll explore different approaches to convert a byte array to a numeric value (int, long, float, double) and vice versa.
在本教程中,我们将探讨将字节数组转换为数字值(int, long, float, double)的不同方法,反之亦然。
The byte is the basic unit of information in computer storage and processing. The primitive types defined in the Java language are a convenient way to manipulate multiple bytes at the same time. Therefore, there is an inherent conversion relationship between a byte array and primitive types.
字节是计算机存储和处理中的基本信息单位。Java语言中定义的原始类型是一种同时操作多个字节的便捷方式。因此,字节阵列和原始类型之间存在固有的转换关系。
Since the short and char types consist of only two bytes, they don’t need much attention. So, we will focus on the conversion between a byte array and int, long, float, and double types.
由于short和char类型仅由两个字节组成,它们不需要太多关注。因此,我们将重点关注byte数组与int、long、float和double类型之间的转换。
2. Using Shift Operators
2.使用移位操作符
The most straightforward way of converting a byte array to a numeric value is using the shift operators.
将字节数组转换为数字值的最直接方法是使用shift运算符。
2.1. Byte Array to int and long
2.1.字节数组到int和long
When converting a byte array to an int value, we use the << (left shift) operator:
当把byte数组转换为int值时,我们使用<<(左移)操作符。
int value = 0;
for (byte b : bytes) {
value = (value << 8) + (b & 0xFF);
}
Normally, the length of the bytes array in the above code snippet should be equal to or less than four. That’s because an int value occupies four bytes. Otherwise, it will lead to the int range overflow.
通常情况下,上述代码片断中的bytes数组的长度应该等于或小于4。这是因为一个int值占用四个字节。否则,会导致int范围溢出。
To verify the correctness of the conversion, let’s define two constants:
为了验证转换的正确性,我们来定义两个常数。
byte[] INT_BYTE_ARRAY = new byte[] {
(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE
};
int INT_VALUE = 0xCAFEBABE;
If we look closely at these two constants, INT_BYTE_ARRAY and INT_VALUE, we’ll find that they’re different representations of the hexadecimal number 0xCAFEBABE.
如果我们仔细观察这两个常量,INT_BYTE_ARRAY和INT_VALUE,我们会发现它们是十六进制数字0xCAFEBABE的不同表示。
Then, let’s check whether this conversion is correct:
然后,让我们检查一下这种转换是否正确。
int value = convertByteArrayToIntUsingShiftOperator(INT_BYTE_ARRAY);
assertEquals(INT_VALUE, value);
Similarly, when converting a byte array to a long value, we can reuse the above code snippet with two modifications: the value‘s type is long and the length of the bytes should be equal to or less than eight.
同样,当把一个字节数组转换为长值时,我们可以重复使用上面的代码片段,但要做两个修改:值的类型是长,并且字节的长度应等于或小于8。
2.2. int and long to Byte Array
2.2.int和long到字节数组
When converting an int value to a byte array, we can use the >> (signed right shift) or the >>> (unsigned right shift) operator:
当将一个int值转换为byte数组时,我们可以使用>>(有符号右移)或>>(无符号右移)操作符。
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;
}
In the above code snippet, we can replace the >> operator with the >>> operator. That’s because we only use the bytes that the value parameter originally contains. So, the right shift with sign-extension or zero-extension won’t affect the final result.
在上面的代码片断中,我们可以用>>操作符代替>>操作符。这是因为我们只使用value参数最初包含的字节。所以,用符号扩展或零扩展的右移不会影响最终的结果。
Then, we can check the correctness of the above conversion:
然后,我们可以检查上述转换的正确性。
byte[] bytes = convertIntToByteArrayUsingShiftOperator(INT_VALUE);
assertArrayEquals(INT_BYTE_ARRAY, bytes);
When converting a long value to a byte array, we only need to change the Integer.BYTES into Long.BYTES and make sure that the type of the value is long.
在将long值转换为byte数组时,我们只需要将Integer.BYTES改为Long.BYTES并确保value的类型为long。
2.3. Byte Array to float and double
2.3.字节数组转为浮点运算和双数
When converting a byte array to a float, we make use of the Float.intBitsToFloat() method:
当将byte数组转换为float时,我们使用了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);
From the code snippet above, we can learn that a byte array can’t be transformed directly into a float value. Basically, it takes two separate steps: First, we transfer from a byte array to an int value, and then we interpret the same bit pattern into a float value.
从上面的代码片段中,我们可以了解到,一个字节数组不能直接转化为浮点值。基本上,它需要两个独立的步骤。首先,我们从字节数组转移到int值,然后我们将相同的位模式解释为float值。
To verify the correctness of the conversion, let’s define two constants:
为了验证转换的正确性,我们来定义两个常数。
byte[] FLOAT_BYTE_ARRAY = new byte[] {
(byte) 0x40, (byte) 0x48, (byte) 0xF5, (byte) 0xC3
};
float FLOAT_VALUE = 3.14F;
Then, let’s check whether this conversion is correct:
然后,让我们检查一下这种转换是否正确。
float value = convertByteArrayToFloatUsingShiftOperator(FLOAT_BYTE_ARRAY);
assertEquals(Float.floatToIntBits(FLOAT_VALUE), Float.floatToIntBits(value));
In the same way, we can utilize an intermediate long value and the Double.longBitsToDouble() method to convert a byte array to a double value.
同样,我们可以利用一个中间的long值和Double.longBitsToDouble()方法来将一个byte数组转换为double值。
2.4. float and double to Byte Array
2.4.float和double到字节数组
When converting a float to a byte array, we can take advantage of the Float.floatToIntBits() method:
当将float转换为byte数组时,我们可以利用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;
}
Then, let’s check whether this conversion is correct:
然后,让我们检查一下这种转换是否正确。
byte[] bytes = convertFloatToByteArrayUsingShiftOperator(FLOAT_VALUE);
assertArrayEquals(FLOAT_BYTE_ARRAY, bytes);
By analogy, we can make use of the Double.doubleToLongBits() method to convert a double value to a byte array.
以此类推,我们可以利用Double.doubleToLongBits()方法将double值转换为byte数组。
3. Using ByteBuffer
3.使用ByteBuffer
The java.nio.ByteBuffer class provides a neat, unified way to translate between a byte array and a numeric value (int, long, float, double).
java.nio.ByteBuffer类提供了一种整洁、统一的方式来转换字节数组和数字值(int, long, float, double)。
3.1. Byte Array to Numeric Value
3.1.字节数组到数值
Now, we use the ByteBuffer class to convert a byte array to an int value:
现在,我们使用ByteBuffer类来将byte数组转换为int值。
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
buffer.put(bytes);
buffer.rewind();
int value = buffer.getInt();
Then, we use the ByteBuffer class to convert an int value to a byte array:
然后,我们使用ByteBuffer类来将int值转换为byte数组。
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
buffer.putInt(value);
buffer.rewind();
byte[] bytes = buffer.array();
We should note that the above two code snippets follow the same pattern:
我们应该注意到,上述两个代码片断遵循相同的模式。
- First, we use the ByteBuffer.allocate(int) method to get a ByteBuffer object with a specified capacity.
- Then, we put the original value (a byte array or an int value) into the ByteBuffer object, such as buffer.put(bytes) and buffer.putInt(value) methods.
- After that, we reset the position of the ByteBuffer object to zero, so we can read from the start.
- Finally, we get the target value from the ByteBuffer object, using such methods as buffer.getInt() and buffer.array().
This pattern is very versatile, and it supports the conversion of long, float, and double types. The only modification we need to make is the type-related information.
这种模式非常通用,它支持long、float和double类型的转换。我们需要做的唯一修改是与类型相关的信息。
3.2. Using an Existing Byte Array
3.2.使用一个现有的字节数组
Additionally, the ByteBuffer.wrap(byte[]) method allows us to reuse an existing byte array without creating a new one:
此外,ByteBuffer.wrap(byte[])方法允许我们重用现有的byte数组,而无需创建一个新的数组。
ByteBuffer.wrap(bytes).getFloat();
However, we should also note that the length of the bytes variable above is equal to or greater than the size of the target type (Float.BYTES). Otherwise, it will throw BufferUnderflowException.
然而,我们还应该注意,上面的bytes变量的长度等于或大于目标类型的大小(Float.BYTES)。否则,它将抛出BufferUnderflowException。
4. Using BigInteger
4.使用BigInteger
The main purpose of the java.math.BigInteger class is to represent large numeric values that would otherwise not fit within a primitive data type. Even though we can use it to convert between a byte array and a primitive value, using BigInteger is a bit heavy for this kind of purpose.
java.math.BigInteger类的主要目的是为了表示大的数值,否则就不适合用原始数据类型。尽管我们可以用它在byte数组和原始值之间进行转换,但使用BigInteger对于这种目的来说有点沉重。
4.1. Byte Array to int and long
4.1.字节数组到int和long
Now, let’s use the BigInteger class to convert a byte array to an int value:
现在,让我们使用BigInteger类来将byte数组转换为int值。
int value = new BigInteger(bytes).intValue();
Similarly, the BigInteger class has a longValue() method to convert a byte array to a long value:
类似地,BigInteger类有一个longValue()方法,将byte数组转换为long值。
long value = new BigInteger(bytes).longValue();
Moreover, the BigInteger class also has an intValueExact() method and a longValueExact() method. These two methods should be used carefully: if the BigInteger object is out of the range of an int or a long type, respectively, both methods will throw an ArithmeticException.
此外,BigInteger类也有一个intValueExact()方法和一个longValueExact()方法。应该谨慎使用这两个方法:如果BigInteger对象分别超出了int或long类型的范围,这两个方法将抛出ArithmeticException。
When converting an int or a long value to a byte array, we can use the same code snippet:
当将int或long值转换为byte数组时,我们可以使用相同的代码片段。
byte[] bytes = BigInteger.valueOf(value).toByteArray();
However, the toByteArray() method of the BigInteger class returns the minimum number of bytes, not necessarily four or eight bytes.
然而,BigInteger类的toByteArray()方法返回最小的字节数,不一定是4或8个字节。
4.2. Byte Array to float and double
4.2.将字节数组转换为float和double
Although the BigInteger class has a floatValue() method, we can’t use it to convert a byte array to a float value as expected. So, what should we do? We can use an int value as an intermediate step to convert a byte array into a float value:
虽然BigInteger类有一个floatValue()方法,但我们不能像预期的那样用它来将byte数组转换成float值。那么,我们应该怎么做呢?我们可以使用一个int值作为中间步骤,将byte数组转换为float值。
int intValue = new BigInteger(bytes).intValue();
float value = Float.intBitsToFloat(intValue);
In the same way, we can convert a float value into a byte array:
以同样的方式,我们可以将一个float值转换成byte数组。
int intValue = Float.floatToIntBits(value);
byte[] bytes = BigInteger.valueOf(intValue).toByteArray();
Likewise, by taking advantage of the Double.longBitsToDouble() and Double.doubleToLongBits() methods, we can use the BigInteger class to convert between a byte array and a double value.
同样,通过利用Double.longBitsToDouble()和Double.doubleToLongBits()方法,我们可以使用BigInteger类在byte数组和double值之间转换。
5. Using Guava
5.使用番石榴
The Guava library provides us with convenient methods to do this kind of conversion.
Guava库为我们提供了方便的方法来进行这种转换。
5.1. Byte Array to int and long
5.1.字节数组到int和long
Within Guava, the Ints class in the com.google.common.primitives package contains a fromByteArray() method. Hence, it’s fairly easy for us to convert a byte array to an int value:
在Guava中,com.google.com.primitives包中的Ints类包含一个fromByteArray()方法。因此,我们可以很容易地将一个byte数组转换为int值。
int value = Ints.fromByteArray(bytes);
The Ints class also has a toByteArray() method that can be used to convert an int value to a byte array:
Ints类也有一个toByteArray()方法,可以用来将一个int值转换为byte数组。
byte[] bytes = Ints.toByteArray(value);
And, the Longs class is similar in use to the Ints class:
而且,Longs类在使用上与Ints类相似。
long value = Longs.fromByteArray(bytes);
byte[] bytes = Longs.toByteArray(value);
Furthermore, if we inspect the source code of the fromByteArray() and toByteArray() methods, we can find out that both methods use shift operators to do their tasks.
此外,如果我们检查fromByteArray()和toByteArray()方法的源代码,我们可以发现这两个方法都使用移位运算符来完成任务。
5.2. Byte Array to float and double
5.2.将字节数组转换为float和double
There also exist the Floats and Doubles classes in the same package. But, neither of these two classes support the fromByteArray() and toByteArray() methods.
在同一个包中还存在Floats和Doubles类。但是,这两个类都不支持fromByteArray()和toByteArray()方法。
However, we can make use of the Float.intBitsToFloat(), Float.floatToIntBits(), Double.longBitsToDouble(), and Double.doubleToLongBits() methods to complete the conversion between a byte array and a float or double value. For brevity, we have omitted the code here.
然而,我们可以利用Float.intBitsToFloat()、Float.floatToIntBits()、Double.longBitsToDouble()和Double.doubleToLongBits()方法来完成byte阵列与float或double值间的转换。为了简洁起见,我们在此省略了代码。
6. Using Commons Lang
6.使用Commons Lang
When we are using Apache Commons Lang 3, it’s a bit complicated to do these kinds of conversions. That’s because the Commons Lang library uses little-endian byte arrays by default. However, the byte arrays we mentioned above are all in big-endian order. Thus, we need to transform a big-endian byte array to a little-endian byte array and vice versa.
当我们使用Apache Commons Lang 3时,要进行这类转换有点复杂。这是因为Commons Lang库默认使用小-endian byte数组。然而,我们上面提到的byte数组都是大-endian的顺序。因此,我们需要将一个大-endian byte数组转换为小-endian byte数组,反之亦然。
6.1. Byte Array to int and long
6.1.字节数组到int和long
The Conversion class in the org.apache.commons.lang3 package provides byteArrayToInt() and intToByteArray() methods.
org.apache.commons.lang3包中的Conversion类提供byteArrayToInt()和intToByteArray()方法。
Now, let’s convert a byte array into an int value:
现在,让我们把一个字节数组转换成int值。
byte[] copyBytes = Arrays.copyOf(bytes, bytes.length);
ArrayUtils.reverse(copyBytes);
int value = Conversion.byteArrayToInt(copyBytes, 0, 0, 0, copyBytes.length);
In the above code, we make a copy of the original bytes variable. This is because sometimes, we do not want to change the contents of the original byte array.
在上面的代码中,我们对原始bytes变量进行了复制。这是因为有时候,我们不想改变原始byte数组的内容。
Then, let’s convert an int value into a byte array:
然后,让我们把一个int值转换成byte数组。
byte[] bytes = new byte[Integer.BYTES];
Conversion.intToByteArray(value, 0, bytes, 0, bytes.length);
ArrayUtils.reverse(bytes);
The Conversion class also defines the byteArrayToLong() and longToByteArray() methods. And, we can use these two methods to transform between a byte array and a long value.
Conversion类还定义了byteArrayToLong()和longToByteArray()方法。而且,我们可以使用这两个方法在byte数组和long值之间转换。
6.2. Byte Array to float and double
6.2.将字节数组转换为float和double
However, the Conversion class doesn’t directly provide the corresponding methods to convert a float or double value.
然而,Conversion类并没有直接提供相应的方法来转换float或double值。
Again, we need an intermediate int or long value to transform between a byte array and a float or double value.
同样,我们需要一个中间的int或long值来转换byte数组和float或double值。
7. Conclusion
7.结语
In this article, we illustrated various ways to convert a byte array to a numeric value using plain Java through shift operators, ByteBuffer, and BigInteger. Then, we saw the corresponding conversions using Guava and Apache Commons Lang.
在这篇文章中,我们通过移位操作符、ByteBuffer和BigInteger,说明了使用普通Java将字节数组转换为数字值的各种方法。然后,我们看到了使用Guava和Apache Commons Lang进行的相应转换。
As usual, the source code for this tutorial can be found over on GitHub.
像往常一样,本教程的源代码可以在GitHub上找到超过。