1. 概述

本文将探讨在Java中将字节数组(byte[])与数值类型(intlongfloatdouble)相互转换的多种方法。字节是计算机存储和处理的基本单位,而Java中的基本类型则是操作多字节的便捷方式。因此,字节数组与基本类型之间存在天然的转换关系。

由于shortchar仅占2字节,转换相对简单,本文将重点讨论intlongfloatdouble类型的转换。

2. 使用位移运算符

位移运算符是实现字节数组与数值类型转换最直接的方式。

2.1 字节数组转int和long

将字节数组转换为int时,使用左移运算符(<<):

int value = 0;
for (byte b : bytes) {
    value = (value << 8) + (b & 0xFF);
}

注意:字节数组长度应≤4(int占4字节),否则会导致溢出。

验证转换正确性:

byte[] INT_BYTE_ARRAY = new byte[] {
    (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE
};
int INT_VALUE = 0xCAFEBABE;

int value = convertByteArrayToIntUsingShiftOperator(INT_BYTE_ARRAY);
assertEquals(INT_VALUE, value);

转换为long时只需修改两处:

  1. value类型改为long
  2. 字节数组长度≤8

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 >>>= 8
}

说明:此处>>>>>效果相同,因为只保留原字节内容。

验证转换:

byte[] bytes = convertIntToByteArrayUsingShiftOperator(INT_VALUE);
assertArrayEquals(INT_BYTE_ARRAY, bytes);

转换为long时只需:

  • Integer.BYTES改为Long.BYTES
  • 确保value类型为long

2.3 字节数组转float和double

转换字节数组为float需分两步:

  1. 先转为int
  2. 通过Float.intBitsToFloat()解释位模式
    // 字节数组转int
    int intValue = 0;
    for (byte b : bytes) {
     intValue = (intValue << 8) + (b & 0xFF);
    }
    // int转float
    float value = Float.intBitsToFloat(intValue);
    

验证转换:

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时,使用long作为中间类型和Double.longBitsToDouble()方法。

2.4 float和double转字节数组

float转为字节数组:

// float转int
int intValue = Float.floatToIntBits(value);
// int转字节数组
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时,使用Double.doubleToLongBits()long类型。

3. 使用ByteBuffer

java.nio.ByteBuffer提供了统一的转换方式,简洁且优雅。

3.1 字节数组与数值类型互转

字节数组转int

ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
buffer.put(bytes);
buffer.rewind(); // 重置position到0
int value = buffer.getInt();

int转字节数组:

ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
buffer.putInt(value);
buffer.rewind();
byte[] bytes = buffer.array();

通用模式

  1. 分配指定大小的ByteBuffer
  2. 放入原始数据(put()putInt()等)
  3. 重置position(rewind()
  4. 获取目标数据(getInt()array()

优势:支持所有数值类型(long/float/double),只需修改类型相关常量(如Long.BYTES)。

3.2 复用现有字节数组

使用ByteBuffer.wrap()避免创建新数组:

float value = ByteBuffer.wrap(bytes).getFloat();

踩坑点:确保字节数组长度≥目标类型大小(如Float.BYTES),否则抛出BufferUnderflowException

4. 使用BigInteger

java.math.BigInteger主要用于大数运算,虽能实现转换,但略显笨重。

4.1 字节数组转int和long

字节数组转int

int value = new BigInteger(bytes).intValue();

long

long value = new BigInteger(bytes).longValue();

注意:使用intValueExact()/longValueExact()会在溢出时抛出ArithmeticException

反向转换:

byte[] bytes = BigInteger.valueOf(value).toByteArray();

问题toByteArray()返回最小字节数,可能不是4或8字节。

4.2 字节数组转float和double

需借助中间类型转换:

// 字节数组转float
int intValue = new BigInteger(bytes).intValue();
float value = Float.intBitsToFloat(intValue);

// float转字节数组
int intValue = Float.floatToIntBits(value);
byte[] bytes = BigInteger.valueOf(intValue).toByteArray();

类比:转double时使用longDouble.longBitsToDouble()

5. 使用Guava

Guava的com.google.common.primitives包提供了便捷方法。

5.1 字节数组转int和long

字节数组转int

int value = Ints.fromByteArray(bytes);

int转字节数组:

byte[] bytes = Ints.toByteArray(value);

long

long value = Longs.fromByteArray(bytes);
byte[] bytes = Longs.toByteArray(value);

实现原理:底层仍使用位移运算符。

5.2 字节数组转float和double

FloatsDoubles类未提供直接方法,需借助中间类型:

// 字节数组转float
int intValue = Ints.fromByteArray(bytes);
float value = Float.intBitsToFloat(intValue);

// float转字节数组
int intValue = Float.floatToIntBits(value);
byte[] bytes = Ints.toByteArray(intValue);

省略double转换同理,使用LongsDouble方法。

6. 使用Commons Lang

Apache Commons Lang默认使用小端序(little-endian),需额外处理字节序。

6.1 字节数组转int和long

字节数组转int

byte[] copyBytes = Arrays.copyOf(bytes, bytes.length); // 避免修改原数组
ArrayUtils.reverse(copyBytes); // 转为小端序
int value = Conversion.byteArrayToInt(copyBytes, 0, 0, 0, copyBytes.length);

int转字节数组:

byte[] bytes = new byte[Integer.BYTES];
Conversion.intToByteArray(value, 0, bytes, 0, bytes.length);
ArrayUtils.reverse(bytes); // 转回大端序

说明long转换使用byteArrayToLong()longToByteArray()

6.2 字节数组转float和double

无直接方法,需通过中间类型转换:

// 字节数组转float
byte[] copyBytes = Arrays.copyOf(bytes, bytes.length);
ArrayUtils.reverse(copyBytes);
int intValue = Conversion.byteArrayToInt(copyBytes, 0, 0, 0, copyBytes.length);
float value = Float.intBitsToFloat(intValue);

// float转字节数组
int intValue = Float.floatToIntBits(value);
byte[] bytes = new byte[Float.BYTES];
Conversion.intToByteArray(intValue, 0, bytes, 0, bytes.length);
ArrayUtils.reverse(bytes);

7. 总结

本文介绍了Java中字节数组与数值类型转换的多种方法:

  • 位移运算符:最基础高效,但需手动处理字节序
  • ByteBuffer:官方推荐,代码简洁优雅
  • BigInteger:适合大数场景,常规转换略显笨重
  • Guava:API友好,底层仍用位移运算
  • Commons Lang:需注意字节序问题,代码稍显繁琐

建议:优先使用ByteBuffer,兼顾性能与可读性;若项目已集成Guava,可考虑其工具类。

完整代码示例请参考GitHub


原始标题:Convert a Byte Array to a Numeric Representation in Java | Baeldung