- String -> byte[]: 将字符串中的字符按照指定的字符集编码成字节序列。
- byte[] -> String: 将一串字节序列按照指定的字符集解码成字符,并组合成字符串。
核心要点
- 字符集是关键:你必须始终明确指定字符集(如
UTF-8,GBK,ISO-8859-1),如果编码和解码使用的字符集不一致,就会出现乱码。 - 首选 UTF-8:在绝大多数现代应用中,
UTF-8是首选的字符集,它能支持全球几乎所有的语言,并且是互联网上的标准。 - 避免使用平台默认字符集:不要使用
String.getBytes()或new String(byte[])这种不带字符集参数的方法,因为它们会使用 JVM 运行时所在操作系统的默认字符集(如 Windows 可能是GBK,Linux/macOS 可能是UTF-8),这会导致代码在不同环境下产生不一致的结果,是乱码的主要来源。
String 转 byte[] (编码)
使用 String 类的 getBytes() 方法。

推荐方式:明确指定字符集
这是最安全、最推荐的做法。
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
public class StringToBytes {
public static void main(String[] args) {
String str = "你好,Java! Hello, World!";
// --- 推荐方式:使用 StandardCharsets (Java 7+) ---
// StandardCharsets 是一个枚举类,提供了标准的字符集常量,比字符串更安全,不会有拼写错误。
try {
byte[] utf8Bytes = str.getBytes(StandardCharsets.UTF_8);
System.out.println("UTF-8 字节数组: " + java.util.Arrays.toString(utf8Bytes));
byte[] gbkBytes = str.getBytes("GBK"); // 也可以直接传入字符集名称字符串
System.out.println("GBK 字节数组: " + java.util.Arrays.toString(gbkBytes));
} catch (UnsupportedEncodingException e) {
// 对于 StandardCharsets.UTF_8 这种标准字符集,这个异常理论上不会发生
// 但对于传入字符串名称的方式,如果字符集不支持,则会抛出此异常
e.printStackTrace();
}
// --- 不推荐的方式:使用平台默认字符集 ---
// 代码在不同操作系统上运行结果可能不同,可能导致问题。
byte[] defaultBytes = str.getBytes();
System.out.println("默认字符集字节数组: " + java.util.Arrays.toString(defaultBytes));
}
}
输出分析:
你会看到 UTF-8 和 GBK 编码后的字节数组是完全不同的,这就是为什么必须指定字符集的原因。
byte[] 转 String (解码)
使用 String 的构造函数。
推荐方式:明确指定字符集
import java.nio.charset.StandardCharsets;
public class BytesToString {
public static void main(String[] args) {
// 假设这是从网络或文件中读取的字节数据,它原本是用 UTF-8 编码的
byte[] utf8Bytes = {-28, -72, -83, -26, -106, -121, 44, 74, 97, 118, 97, 33, 32, 72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33};
// --- 推荐方式:使用与编码时相同的字符集 ---
String strFromUtf8 = new String(utf8Bytes, StandardCharsets.UTF_8);
System.out.println("从 UTF-8 字节数组解码: " + strFromUtf8);
// --- 错误示范:使用了错误的字符集 ---
// 如果我们错误地用 GBK 去解码一个 UTF-8 编码的字节数组,就会出现乱码
String strFromGbk = new String(utf8Bytes, "GBK");
System.out.println("错误地用 GBK 解码 UTF-8 字节 (乱码): " + strFromGbk);
// --- 另一个错误示范:使用平台默认字符集 ---
// 同样,不推荐使用
String strFromDefault = new String(utf8Bytes);
System.out.println("用默认字符集解码: " + strFromDefault);
}
}
输出分析:

从 UTF-8 字节数组解码: 正确地输出了 "你好,Java! Hello, World!"。错误地用 GBK 解码 UTF-8 字节 (乱码): 会输出一堆看不懂的字符,这就是乱码。用默认字符集解码: 结果取决于你当前运行代码的系统的默认编码,可能是对的,也可能是错的。
常见问题与最佳实践
问题1:处理不完整的字节序列
byte[] 不是一个完整的字符序列(截断了多字节字符的某一部分),用 new String() 解码时会抛出 MalformedInputException 或用替换字符()代替。
import java.nio.charset.StandardCharsets;
import java.nio.charset.MalformedInputException;
public class IncompleteByteSequence {
public static void main(String[] args) {
// "中" 字的 UTF-8 编码是 3 个字节: [-28, -72, -83]
byte[] incompleteBytes = {-28, -72}; // 只取了前两个字节
try {
// 这会抛出异常,因为这是一个不完整的 UTF-8 序列
String str = new String(incompleteBytes, StandardCharsets.UTF_8);
System.out.println(str);
} catch (MalformedInputException e) {
System.err.println("错误:输入的字节序列不完整或格式错误!");
}
}
}
最佳实践:如何正确处理不完整数据?
在网络传输中,数据分片接收是很常见的,你需要一个策略来处理这种情况。
- 丢弃不完整的数据:最简单粗暴,直接忽略最后一个不完整的字符。
- 使用
CharsetDecoder:这是最灵活、最强大的方式。CharsetDecoder可以让你配置如何处理错误,例如用替换符代替错误序列。
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.MalformedInputException;
public class SafeDecoder {
public static void main(String[] args) throws CharacterCodingException {
byte[] incompleteBytes = {-28, -72}; // "中" 字不完整的 UTF-8 编码
// --- 方式一:严格模式(默认)---
try {
String strictStr = new String(incompleteBytes, StandardCharsets.UTF_8);
System.out.println("严格模式解码: " + strictStr);
} catch (MalformedInputException e) {
System.out.println("严格模式解码失败: " + e.getMessage());
}
// --- 方式二:宽松模式(用替换符 � 代替错误序列)---
CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE) // 遇到不完整序列时替换
.onUnmappableCharacter(CodingErrorAction.REPLACE); // 遇到无法映射的字符时替换
try {
CharBuffer charBuffer = decoder.decode(ByteBuffer.wrap(incompleteBytes));
String lenientStr = charBuffer.toString();
System.out.println("宽松模式解码: " + lenientStr); // 输出 "�"
} catch (CharacterCodingException e) {
e.printStackTrace();
}
}
}
总结表格
| 操作 | 推荐方法 | 说明 |
|---|---|---|
| String -> byte[] | str.getBytes(StandardCharsets.UTF_8) |
必须指定字符集。StandardCharsets 是 Java 7+ 的安全选择。 |
| byte[] -> String | new String(byte[], StandardCharsets.UTF_8) |
必须使用与编码时相同的字符集,否则会乱码。 |
| 处理不完整字节 | 使用 CharsetDecoder 并设置 CodingErrorAction |
在网络或流式数据处理中非常有用,可以更优雅地处理错误。 |
| 避免 | str.getBytes() 和 new String(byte[]) |
依赖平台默认字符集,是导致跨平台乱码的罪魁祸首,应绝对避免。 |
记住这个黄金法则:编码和解码必须使用同一种字符集,并且永远不要依赖默认值。

