什么是 byte 数组?
byte 数组是 byte 类型的元素的集合,在 Java 中,byte 是一种基本数据类型,占用 8 位(1个字节) 的内存空间。byte 数组非常适合用来表示和操作原始的二进制数据,

- (图片、视频、音频、可执行文件等)
- 网络数据包
- 内存中的二进制数据块
- 加密/解密后的数据
创建和初始化
// 1. 创建一个指定长度的 byte 数组,元素会被初始化为 0
byte[] byteArray1 = new byte[10];
System.out.println(Arrays.toString(byteArray1)); // 输出: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
// 2. 创建并初始化 byte 数组
byte[] byteArray2 = {0x01, 0x02, 0x03, 0x04}; // 使用十六进制表示
System.out.println(Arrays.toString(byteArray2)); // 输出: [1, 2, 3, 4]
// 3. 从 String 创建 byte 数组 (使用平台默认的字符编码,如 UTF-8)
String str = "Hello";
byte[] byteArray3 = str.getBytes();
System.out.println(Arrays.toString(byteArray3)); // 输出: [72, 101, 108, 108, 111]
// 4. 从 String 创建 byte 数组并指定编码 (推荐)
try {
byte[] byteArray4 = str.getBytes("UTF-8");
System.out.println(Arrays.toString(byteArray4)); // 输出同上
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
byte 与二进制、十六进制的转换
这是处理二进制数据时最常见的操作。
byte 的取值范围
一个 byte 是 8 位,所以它的范围是:
- 有符号: -128 到 127
- 无符号: 0 到 255
Java 的 byte 类型是有符号的,当我们想把它当作一个 0-255 的无符号值来处理时,需要一些转换技巧。
将 byte 转换为二进制字符串
public static String byteToBinaryString(byte b) {
// 使用 Integer.toBinaryString(),它会将 byte 自动提升为 int
// 但对于负数,它会显示 32 位的补码形式,所以我们只取最后 8 位
return String.format("%8s", Integer.toBinaryString(b & 0xFF))
.replace(' ', '0');
}
byte b = -5; // 二进制补码表示为 11111011
System.out.println(byteToBinaryString(b)); // 输出: 11111011
解释 b & 0xFF:

0xFF是十六进制,代表二进制的0000000011111111(一个 int)。b会被提升为int,b是负数,高位会补 1。-5(byte) 提升为 int 后是11111111111111111111111111111011。- 进行
&运算后,高 24 位被清零,只剩下低 8 位,这样我们就得到了11111011,并且它被当作一个无符号的 int 值(251)来处理,避免了Integer.toBinaryString()对负数的特殊处理。
将 byte 转换为十六进制字符串
public static String byteToHexString(byte b) {
// 同样,使用 b & 0xFF 来确保正确处理
return String.format("%02X", b & 0xFF);
}
byte b = 15;
System.out.println(byteToHexString(b)); // 输出: 0F
byte b2 = -5;
System.out.println(byteToHexString(b2)); // 输出: FB
%02X是一个格式化字符串:%X: 将整数格式化为大写十六进制。02: 总共占 2 位,如果不足,在前面补 0。
byte 数组的常用操作
遍历和打印
byte[] data = {0x01, 0x0A, (byte)0xFF, (byte)0x80}; // 注意-128(0x80)需要强制转换
// 1. 直接打印 (输出的是十进制表示)
System.out.println(Arrays.toString(data)); // 输出: [1, 10, -1, -128]
// 2. 遍历并打印每个字节(十六进制格式)
for (byte b : data) {
System.out.print(String.format("%02X ", b & 0xFF));
}
// 输出: 01 0A FF 80
byte 数组与 String 的互转
// String -> byte[]
String originalString = "Java 字符串";
try {
// 指定编码(强烈推荐)
byte[] utf8Bytes = originalString.getBytes("UTF-8");
System.out.println("UTF-8 字节数组长度: " + utf8Bytes.length);
byte[] gbkBytes = originalString.getBytes("GBK");
System.out.println("GBK 字节数组长度: " + gbkBytes.length);
// byte[] -> String
String decodedFromUTF8 = new String(utf8Bytes, "UTF-8");
System.out.println("从 UTF-8 解码: " + decodedFromUTF8);
String decodedFromGBK = new String(gbkBytes, "GBK");
System.out.println("从 GBK 解码: " + decodedFromGBK);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
重要提示: 字符编码是处理 byte 数组和 String 之间转换时最关键的一环,错误的编码会导致乱码()。
子数组 (Arrays.copyOfRange)
byte[] source = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// 复制从索引 2 开始,长度为 4 的子数组
byte[] subArray = Arrays.copyOfRange(source, 2, 6); // 结束索引是 exclusive 的
System.out.println(Arrays.toString(subArray)); // 输出: [2, 3, 4, 5]
比较数组 (Arrays.equals)
byte[] a1 = {1, 2, 3};
byte[] a2 = {1, 2, 3};
byte[] a3 = {1, 2, 4};
System.out.println(Arrays.equals(a1, a2)); // 输出: true
System.out.println(Arrays.equals(a1, a3)); // 输出: false
高级二进制操作:ByteBuffer
当需要对 byte 数组进行复杂的读写操作(如写入/读取 int, long, float, double 等多字节数据类型)时,使用 java.nio.ByteBuffer 会非常方便和高效,它避免了手动处理字节顺序(大端序/小端序)。
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class ByteBufferExample {
public static void main(String[] args) {
// 1. 创建一个 ByteBuffer
// allocateDirect 使用直接内存,性能更高,适合I/O操作
ByteBuffer buffer = ByteBuffer.allocate(16); // 分配16字节的缓冲区
// 2. 写入数据
buffer.putInt(100); // 写入一个 int (4字节)
buffer.putLong(987654321L); // 写入一个 long (8字节)
buffer.putFloat(3.14f); // 写入一个 float (4字节)
// 3. 准备读取数据:必须调用 flip()!
// flip() 将 limit 设置为 position,并将 position 重置为 0
buffer.flip();
// 4. 读取数据
int intValue = buffer.getInt();
long longValue = buffer.getLong();
float floatValue = buffer.getFloat();
System.out.println("Read Int: " + intValue); // 输出: 100
System.out.println("Read Long: " + longValue); // 输出: 987654321
System.out.println("Read Float: " + floatValue); // 输出: 3.14
// 5. 获取内部的 byte 数组
// 注意:get() 操作会改变 position,所以要在 flip() 之前或使用 duplicate()
buffer.rewind(); // 重置 position 到 0,但不改变 limit
byte[] array = new byte[buffer.remaining()];
buffer.get(array);
System.out.println("Underlying byte array: " + Arrays.toString(array));
// 输出类似: [0, 0, 0, 100, 41, -21, -122, -29, 64, 72, -106, 114, 64, 9, 33, -64]
}
}
字节顺序
网络协议通常规定使用 大端序(Big-Endian,高位字节在前)。
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.order(ByteOrder.BIG_ENDIAN); // 默认就是大端序,但明确指定是好习惯
buffer.putInt(0x12345678);
byte[] bigEndianArray = new byte[4];
buffer.rewind();
buffer.get(bigEndianArray);
System.out.println("Big-Endian: " + Arrays.toString(bigEndianArray)); // 输出: [18, 52, 86, 120]
ByteBuffer littleEndianBuffer = ByteBuffer.allocate(4);
littleEndianBuffer.order(ByteOrder.LITTLE_ENDIAN);
littleEndianBuffer.putInt(0x12345678);
byte[] littleEndianArray = new byte[4];
littleEndianBuffer.rewind();
littleEndianBuffer.get(littleEndianArray);
System.out.println("Little-Endian: " + Arrays.toString(littleEndianArray)); // 输出: [120, 86, 52, 18]
实际应用场景
-
文件 I/O:
(图片来源网络,侵删)FileInputStream和FileOutputStream直接读写byte[]。Files.readAllBytes()和Files.write()可以方便地读写整个文件为byte[]。
try { byte[] fileBytes = Files.readAllBytes(Paths.get("my_image.png")); System.out.println("文件大小: " + fileBytes.length + " 字节"); // ... 对 fileBytes 进行处理 ... Files.write(Paths.get("copy_of_image.png"), fileBytes); } catch (IOException e) { e.printStackTrace(); } -
网络编程:
Socket的getInputStream()和getOutputStream()用于在网络中传输byte[]数据。
-
数据序列化/反序列化:
- 当需要将一个对象或数据结构转换成字节流以便存储或传输时,就会用到
byte[],Java 内置的序列化机制、JSON 库、Protobuf、MessagePack 等最终都会操作byte[]。
- 当需要将一个对象或数据结构转换成字节流以便存储或传输时,就会用到
-
加密与解密:
- 加密算法(如 AES, RSA)的输入和输出都是
byte[]。
- 加密算法(如 AES, RSA)的输入和输出都是
| 概念 | 关键点 |
|---|---|
byte 数组 |
Java 中处理二进制数据的基础,每个元素占 1 字节 (8 bits)。 |
byte 范围 |
有符号:-128 到 127,处理无符号逻辑时,常用 b & 0xFF。 |
| 转换 | Integer.toHexString(b & 0xFF)、String.format() 是格式化的利器。 |
与 String 互转 |
必须指定字符编码(如 UTF-8, GBK),否则可能乱码。 |
| 高级操作 | java.nio.ByteBuffer 是处理复杂二进制数据(读写 int, long 等)的首选,能自动处理字节序。 |
| 应用 | 文件操作、网络通信、数据序列化、加密解密等所有涉及原始二进制数据的场景。 |
掌握 byte 数组及其相关操作是成为一名合格 Java 后端或系统程序员的必备技能。
