核心要点:字符编码
Java 字符串内部使用 UTF-16 编码,当你将其转换为 byte[] 时,你必须选择一种字符编码方案(如 UTF-8, ISO-8859-1, GBK 等)来将字符序列映射到字节序列。

强烈建议始终使用 StandardCharsets.UTF_8,除非你有特殊需求。 UTF-8 是目前互联网上最通用的编码,它可以表示地球上几乎所有的字符,并且向后兼容 ASCII。
使用 String.getBytes()(不推荐,易出错)
这是最直接的方法,但它的行为取决于 JVM 的默认平台编码,不同的操作系统、不同的 JVM 配置,默认编码可能不同(Windows 可能是 GBK,而 Linux/macOS 通常是 UTF-8)。
语法:
byte[] bytes = str.getBytes();
问题示例:

String str = "你好,世界!"; // 在默认编码为 GBK 的 JVM 上运行 byte[] bytes = str.getBytes(); // 使用默认编码 GBK // 在默认编码为 UTF-8 的 JVM 上运行 // byte[] bytes = str.getBytes(); // 使用默认编码 UTF-8 // 如果你在 GBK 环境下生成了 bytes,然后尝试用 UTF-8 去解码,就会得到乱码 String wrongStr = new String(bytes, StandardCharsets.UTF_8); System.out.println(wrongStr); // 输出可能为:浣犲ソ锛屾垨闈�锛�
这种方法会导致代码在不同环境下产生不一致的结果,应尽量避免使用。
使用 String.getBytes(StandardCharsets)(推荐)
这是最安全、最推荐的方法,你显式地指定了编码,使得代码在任何平台上行为都一致。StandardCharsets 是 Java 7 引入的枚举类,包含了最常用的几种编码常量。
使用 UTF-8 编码(最常用)
UTF-8 是一种可变长编码,ASCII 字符占 1 个字节,非 ASCII 字符(如中文)通常占 3 个字节,它是 Web 开发和数据交换的事实标准。
import java.nio.charset.StandardCharsets;
public class StringToBytesExample {
public static void main(String[] args) {
String str = "Hello, 世界!";
// 使用 UTF-8 编码将字符串转换为 byte[]
byte[] utf8Bytes = str.getBytes(StandardCharsets.UTF_8);
System.out.println("原始字符串: " + str);
System.out.println("UTF-8 字节数组: " + java.util.Arrays.toString(utf8Bytes));
System.out.println("字节数组长度: " + utf8Bytes.length); // H(1) e(1) ... (3) 世(3) 界(3) !(1) = 1+1+1+1+1+3+3+1 = 12
// 验证:从字节数组再转回字符串
String decodedStr = new String(utf8Bytes, StandardCharsets.UTF_8);
System.out.println("解码后的字符串: " + decodedStr); // 应该和原始字符串一致
}
}
输出:

原始字符串: Hello, 世界!
UTF-8 字节数组: [72, 101, 108, 108, 111, 44, 32, -28, -72, -83, -27, -101, -67, 33]
字节数组长度: 12
解码后的字符串: Hello, 世界!
使用其他编码
根据你的需求,你也可以使用其他编码,ISO-8859-1(也叫 Latin-1)。
ISO-8859-1 的特点:
- 它是一种单字节编码,每个字符固定占 1 个字节。
- 它无法表示中文字符,所有非 ASCII 字符都会被替换为 。
- 一个非常重要的特性是:它是一种“无损”的编码转换,也就是说,
byte[] -> ISO-8859-1 String -> byte[]的过程是双向可逆的,不会丢失任何信息,这使得它有时被用作一种“二进制数据的字符串表示”的中间格式。
import java.nio.charset.StandardCharsets;
public class StringToBytesExample_ISO {
public static void main(String[] args) {
String str = "Hello, 世界!";
// 使用 ISO-8859-1 编码
byte[] isoBytes = str.getBytes(StandardCharsets.ISO_8859_1);
System.out.println("原始字符串: " + str);
System.out.println("ISO-8859-1 字节数组: " + java.util.Arrays.toString(isoBytes));
System.out.println("字节数组长度: " + isoBytes.length); // 所有字符都占 1 个字节,长度为 10
// 验证:从字节数组再转回字符串
String decodedStr = new String(isoBytes, StandardCharsets.ISO_8859_1);
System.out.println("解码后的字符串: " + decodedStr); // 中文字符会丢失,变成问号
}
}
输出:
原始字符串: Hello, 世界!
ISO-8859-1 字节数组: [72, 101, 108, 108, 111, 44, 32, 63, 63, 33]
字节数组长度: 10
解码后的字符串: Hello, ?!?
使用 String.getBytes(String charsetName)(较旧)
在 Java 7 之前,没有 StandardCharsets,人们通常使用这个方法,通过传入一个编码名称的字符串(如 "UTF-8")来指定编码。
语法:
byte[] bytes = str.getBytes("UTF-8");
缺点:
- 如果传入的编码名称无效,会抛出
UnsupportedEncodingException,需要你try-catch处理。 - 字符串形式的编码名不如
StandardCharsets枚举类型安全(编译器无法检查)。
import java.io.UnsupportedEncodingException;
public class StringToBytesExample_Old {
public static void main(String[] args) {
String str = "Hello, 世界!";
try {
// 使用旧的指定编码名称的方式
byte[] bytes = str.getBytes("UTF-8");
System.out.println("字节数组: " + java.util.Arrays.toString(bytes));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
如果你的代码可以运行在 Java 7 或更高版本,优先使用 StandardCharsets,因为它更简洁、更安全。
总结与最佳实践
| 方法 | 语法 | 优点 | 缺点 | 推荐度 |
|---|---|---|---|---|
| 默认编码 | str.getBytes() |
简单 | 依赖平台,不可预测,易导致乱码 | ⭐ (不推荐) |
| 推荐方式 | str.getBytes(StandardCharsets.UTF_8) |
安全、跨平台、明确、不抛出异常 | 无 | ⭐⭐⭐⭐⭐ (强烈推荐) |
| 旧版方式 | str.getBytes("UTF-8") |
可指定编码 | 需要处理 UnsupportedEncodingException |
⭐⭐ (仅在旧Java项目中使用) |
| 特殊场景 | str.getBytes(StandardCharsets.ISO_8859_1) |
单字节,可逆,适合处理二进制数据 | 无法表示多字节字符(如中文) | ⭐⭐ (特定场景使用) |
最佳实践:
- 默认使用 UTF-8: 在绝大多数情况下,使用
String.getBytes(StandardCharsets.UTF_8)是你的首选。 - 明确编码: 在代码中始终显式地指定编码,不要依赖任何默认值。
- 处理二进制数据: 如果你需要将字节数组视为一个“不可打印”的二进制流,并且希望它能被
String安全地“包装”和“解包”(在网络传输中),使用StandardCharsets.ISO_8859_1是一个巧妙的技巧,因为它保证了byte[]和String之间的无损转换。
