核心概念:为什么需要编码?
计算机只认识 0 和 1(字节),字符串是 char 类型的序列,而 char 在 Java 中是 16 位的 Unicode 字符,为了将字符串存储到文件、在网络中传输或存入数据库,必须将这些 char 转换为一系列的字节。

字符编码就是一套规则,规定了如何将字符映射到字节序列,最常用的编码是 UTF-8。
使用 String.getBytes()(不推荐,除非你明确知道后果)
这是最直接的方法,但它依赖于平台默认的字符编码。
public class StringToByteExample {
public static void main(String[] args) {
String str = "你好,Java!";
// 使用平台默认的字符编码进行转换
// 在中文 Windows 系统上,默认可能是 GBK
// 在 Linux 或 macOS 上,默认通常是 UTF-8
byte[] bytes = str.getBytes();
System.out.println("原始字符串: " + str);
System.out.println("转换后的字节数组: " + Arrays.toString(bytes));
}
}
为什么不推荐? 因为“平台默认编码”是不可靠的,你的代码在你的电脑上运行正常,但部署到另一台使用不同默认编码的服务器上时,就可能产生乱码,这会导致难以排查的“间歇性”bug。
使用 String.getBytes(StandardCharsets.UTF_8)(推荐,最常用)
这是最推荐、最安全的方式,显式地指定使用 UTF-8 编码,可以确保你的代码在任何平台上行为一致,避免乱码问题。

StandardCharsets 是 Java 7 引入的一个枚举类,它预定义了几个最常用的字符集常量(UTF_8, ISO_8859_1, US_ASCII),使用它比直接传入字符串(如 "UTF-8")更高效、更安全。
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class StringToByteRecommended {
public static void main(String[] args) {
String str = "你好,Java!";
// 强制使用 UTF-8 编码进行转换
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
System.out.println("原始字符串: " + str);
System.out.println("使用 UTF-8 编码转换后的字节数组: " + Arrays.toString(bytes));
}
}
输出示例:
原始字符串: 你好,Java!
使用 UTF-8 编码转换后的字节数组: [-60, -29, -70, -61, -43, -48, -50, -68, -77, -25, -68, -68, -103]
这个输出是跨平台一致的。
使用 String.getBytes(String charsetName)(需要处理异常)
如果你需要使用非标准的字符集(如 GBK, ISO-8859-1),可以使用这个重载方法,但它会抛出 UnsupportedEncodingException 异常,因此必须用 try-catch 包裹。

import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class StringToByteWithCharset {
public static void main(String[] args) {
String str = "你好,Java!";
try {
// 使用 GBK 编码进行转换
byte[] gbkBytes = str.getBytes("GBK");
System.out.println("使用 GBK 编码转换后的字节数组: " + Arrays.toString(gbkBytes));
// 使用 ISO-8859-1 编码(仅支持 ASCII 字符,中文会乱码)
byte[] isoBytes = str.getBytes("ISO-8859-1");
System.out.println("使用 ISO-8859-1 编码转换后的字节数组: " + Arrays.toString(isoBytes));
} catch (UnsupportedEncodingException e) {
System.err.println("不支持的字符集编码");
e.printStackTrace();
}
}
}
输出示例:
使用 GBK 编码转换后的字节数组: [-60, -29, -70, -61, -43, -48, -50, -68, -77, -25, -68, -68, -103]
使用 ISO-8859-1 编码转换后的字节数组: [63, 63, 63, 63, 63, 74, 97, 118, 97, 33]
注意,使用 ISO-8859-1 时,中文字符无法表示,被替换为了 。
反向操作:byte[] 转 String
将字节数组转换回字符串时,同样必须使用相同的编码,否则会乱码。
import java.nio.charset.StandardCharsets;
public class ByteToStringExample {
public static void main(String[] args) {
String originalStr = "Hello, 世界!";
// 1. 字符串 -> byte[] (使用 UTF-8)
byte[] bytes = originalStr.getBytes(StandardCharsets.UTF_8);
System.out.println("原始字符串: " + originalStr);
System.out.println("字节数组: " + Arrays.toString(bytes));
// 2. byte[] -> 字符串 (必须使用相同的 UTF-8 编码)
String decodedStr = new String(bytes, StandardCharsets.UTF_8);
System.out.println("解码后的字符串: " + decodedStr);
// 3. 错误示范:使用了错误的编码
String wrongStr = new String(bytes, StandardCharsets.ISO_8859_1);
System.out.println("使用错误编码解码后的字符串: " + wrongStr); // 会乱码
}
}
输出:
原始字符串: Hello, 世界!
字节数组: [72, 101, 108, 108, 111, 44, 32, -28, -72, -83, -27, -101, -67, 33]
解码后的字符串: Hello, 世界!
使用错误编码解码后的字符串: Hello, 世界!
可以看到,使用错误的编码解码后,字符串变得不可读。
总结与最佳实践
| 方法 | 描述 | 优点 | 缺点 | 推荐度 |
|---|---|---|---|---|
str.getBytes() |
使用平台默认编码 | 简单 | 不可靠,跨平台时可能乱码 | ⭐☆☆☆☆ (不推荐) |
str.getBytes(StandardCharsets.UTF_8) |
使用指定的 UTF-8 编码 | 可靠、高效、跨平台一致 | 无 | ⭐⭐⭐⭐⭐ (强烈推荐) |
str.getBytes("GBK") |
使用指定的字符集(如 GBK) | 灵活,可用于处理旧系统数据 | 需要处理 UnsupportedEncodingException |
⭐⭐⭐☆☆ (特定场景下使用) |
核心原则:
- 优先使用
StandardCharsets.UTF_8:除非你有特殊需求(需要与一个只支持 GBK 的旧系统交互),否则总是使用StandardCharsets.UTF_8,这是现代软件开发的事实标准。 - 编码和解码必须一致:将字符串转为字节时使用的编码,必须与将字节转回字符串时使用的编码完全相同。
- 避免平台默认编码:永远不要依赖
str.getBytes()的默认行为,因为它会让你的代码变得脆弱和不可预测。
