杰瑞科技汇

Java int 转 byte数组

使用 ByteBuffer (推荐)

这是最现代、最简洁、最安全的方法。java.nio.ByteBuffer 是 Java NIO (New I/O) 包中的一个类,专门用于处理字节数据的读写。

Java int 转 byte数组-图1
(图片来源网络,侵删)

使用 ByteBuffer.allocate()

这种方法会创建一个新的堆内存 ByteBuffer,然后将 int 写入,最后获取其底层的字节数组。

import java.nio.ByteBuffer;
import java.nio.ByteOrder; // 用于指定字节序
public class IntToBytesWithByteBuffer {
    public static void main(String[] args) {
        int intValue = 0x12345678; // 一个示例整数
        // --- 方法 1a: 默认大端序 ---
        // 创建一个容量为 4 (int 大小) 的 ByteBuffer
        ByteBuffer bb = ByteBuffer.allocate(4);
        // 将 int 值放入 ByteBuffer
        bb.putInt(intValue);
        // 获取底层字节数组
        byte[] bigEndianBytes = bb.array();
        System.out.println("默认大端序 (Big-Endian) 字节数组:");
        for (byte b : bigEndianBytes) {
            System.out.printf("%02X ", b);
        }
        // 输出: 12 34 56 78
        System.out.println("\n");
        // --- 方法 1b: 指定小端序 ---
        // 清空 ByteBuffer 或重新创建
        bb.clear();
        // 设置字节序为小端序
        bb.order(ByteOrder.LITTLE_ENDIAN);
        bb.putInt(intValue);
        byte[] littleEndianBytes = bb.array();
        System.out.println("小端序 字节数组:");
        for (byte b : littleEndianBytes) {
            System.out.printf("%02X ", b);
        }
        // 输出: 78 56 34 12
    }
}

优点:

  • 代码简洁易读:API 设计直观,putInt()array() 方法清晰地表达了意图。
  • 线程安全:每个 ByteBuffer 实例是独立的,非常适合多线程环境。
  • 功能强大:除了 int,还可以轻松处理 long, float, double 等多种基本类型。
  • 可指定字节序:通过 order() 方法可以轻松地在大端序小端序 之间切换,这在跨平台通信中至关重要。

使用 ByteBuffer.wrap()

如果你已经有一个 byte 数组,并且想向其中写入 int 数据,可以使用 wrap() 方法。

import java.nio.ByteBuffer;
public class IntToBytesWithWrap {
    public static void main(String[] args) {
        int intValue = 0x12345678;
        byte[] byteArray = new byte[4]; // 准备一个 4 字节的数组
        // 使用 wrap 将数组包装成 ByteBuffer
        ByteBuffer bb = ByteBuffer.wrap(byteArray);
        bb.putInt(intValue); // 将 int 写入数组
        System.out.println("使用 wrap() 的字节数组:");
        for (byte b : byteArray) {
            System.out.printf("%02X ", b);
        }
        // 输出: 12 34 56 78
    }
}

使用 ByteArrayOutputStreamDataOutputStream

这是一种经典的 I/O 流方法,同样非常可靠和易读。

Java int 转 byte数组-图2
(图片来源网络,侵删)
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class IntToBytesWithStream {
    public static void main(String[] args) throws IOException {
        int intValue = 0x12345678;
        // 创建一个字节输出流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 创建一个数据输出流,并包装字节输出流
        try (DataOutputStream dos = new DataOutputStream(baos)) {
            // 将 int 值写入数据流
            dos.writeInt(intValue);
        } // 使用 try-with-resources 确保 dos 和 baos 被自动关闭
        // 获取内部缓冲区的字节数组
        byte[] bytes = baos.toByteArray();
        System.out.println("使用 DataOutputStream 的字节数组:");
        for (byte b : bytes) {
            System.out.printf("%02X ", b);
        }
        // 输出: 12 34 56 78
    }
}

优点:

  • 非常易读:流式操作的概念非常清晰。
  • 功能丰富DataOutputStream 提供了写入所有基本类型的方法(writeInt, writeDouble, writeUTF 等)。
  • 自动处理字节序DataOutputStream 总是使用大端序(网络字节序),符合网络协议标准。

缺点:

  • 相比 ByteBuffer,需要创建更多的对象(ByteArrayOutputStream, DataOutputStream),在性能敏感的循环中可能稍逊一筹。

手动位移操作 (最底层)

这种方法不依赖任何高级类,直接通过位运算来提取 int 的每个字节,这能让你更深刻地理解计算机是如何存储整数的。

public class IntToBytesManually {
    public static byte[] intToBytes(int value) {
        byte[] bytes = new byte[4];
        // 将 value 右移 24 位,得到最高 8 位,然后转换为 byte
        bytes[0] = (byte) (value >>> 24);
        // 将 value 右移 16 位,得到次高 8 位,然后转换为 byte
        bytes[1] = (byte) (value >>> 16);
        // 将 value 右移 8 位,得到次低 8 位,然后转换为 byte
        bytes[2] = (byte) (value >>> 8);
        // value 本身就是最低 8 位,然后转换为 byte
        bytes[3] = (byte) value;
        return bytes;
    }
    public static void main(String[] args) {
        int intValue = 0x12345678;
        byte[] bytes = intToBytes(intValue);
        System.out.println("手动位移的字节数组 (大端序):");
        for (byte b : bytes) {
            System.out.printf("%02X ", b);
        }
        // 输出: 12 34 56 78
    }
}

解释:

Java int 转 byte数组-图3
(图片来源网络,侵删)
  • 一个 int 是 32 位,4 个字节,我们假设内存中是从低地址到高地址依次存放字节 0, 1, 2, 3。
  • bytes[0] 存放最高 8 位,通过 value >>> 24(无符号右移 24 位),将最高 8 位移到最低 8 位的位置。
  • (byte) 类型转换会截断 int 的低 8 位,正好是我们需要的字节值。
  • 注意:Java 的 int 是有符号的,在转换为 byte 时,如果最高位是 1,会发生符号扩展。0xAB 会被转换为 (byte) 0xAB,但如果一个数是 0xFFFFFFAB (即 -85),(byte) 转换后得到的就是 0xAB,而 >>> (无符号右移) 可以确保我们正确地获取到原始位模式,不受符号影响。

优点:

  • 性能最高:没有对象创建和方法调用的开销,是几种方法中最快的。
  • 不依赖任何库:在资源极其受限或需要完全控制内存的环境下很有用。

缺点:

  • 代码可读性差:对于不熟悉位运算的开发者来说,代码难以理解。
  • 容易出错:需要非常小心地处理符号和位移位数。
  • 字节序固定:上面的代码实现的是大端序,如果要实现小端序,需要调整赋值顺序。

总结与对比

方法 优点 缺点 适用场景
ByteBuffer 代码简洁、线程安全、功能强大、可指定字节序 相比位移操作,有少量对象创建开销 绝大多数情况下的首选,尤其是网络编程、文件I/O、复杂序列化/反序列化。
DataOutputStream 代码易读、功能丰富、自动大端序 对象创建开销比 ByteBuffer 稍大 需要将多种数据类型写入流(如写入文件或网络)的场景。
手动位移 性能最高、无外部依赖 代码可读性差、易出错、字节序固定 性能至上的极端场景,或者学习底层原理时使用。

字节序 (Endianness) 的重要提醒

  • 大端序:高位字节在低地址,低位字节在高地址。0x12345678 -> [12, 34, 56, 78],这是网络传输的标准(网络字节序),也是 Java 虚拟机在内存中存储 int 的方式(高位在前)。
  • 小端序:低位字节在低地址,高位字节在高地址。0x12345678 -> [78, 56, 34, 12],这是大多数现代 x86/x64 架构 CPU 在内存中存储 int 的方式。

关键点:Java 的 int 在内存中是大端序存储的,但 CPU 在处理时通常是小端序,当你使用 ByteBufferDataOutputStreamint 转换为字节数组时,默认会生成大端序的字节流,如果你的接收方是小端序的系统(如 x86 PC),你必须进行转换,否则数据就会错乱。

最佳实践:在进行跨平台数据交换时,始终明确指定字节序,通常约定使用大端序(网络字节序)。

分享:
扫描分享到社交APP
上一篇
下一篇