转换时必须明确指定字符编码(Character Encoding)。

核心方法:String 构造函数
Java 的 String 类提供了多个构造函数来从 byte 数组创建字符串,最常用的是以下两个:
public String(byte[] bytes)
- 作用:使用平台的默认字符编码来解码
byte数组。 - 缺点:强烈不推荐,因为不同操作系统(如 Windows、Linux、macOS)的默认编码可能不同(如 Windows 可能是
GBK,Linux/macOS 通常是UTF-8),这会导致你的代码在 A 机器上运行正常,在 B 机器上就出现乱码,代码的可移植性和稳定性会非常差。
public String(byte[] bytes, String charsetName)
- 作用:使用你明确指定的字符编码(
charsetName)来解码byte数组。 - 优点:强烈推荐,代码在任何环境下行为都一致,可移植性好,能有效避免乱码问题。
最佳实践:使用 StandardCharsets (Java 7+)
为了防止拼写错误(比如把 "UTF-8" 写成 "UFT-8"),Java 7 引入了 java.nio.charset.StandardCharsets 类,它提供了一些常用编码的常量。
import java.nio.charset.StandardCharsets;
byte[] bytes = "你好,世界".getBytes(StandardCharsets.UTF_8); // 先得到一个UTF-8编码的字节数组
// 推荐方式:使用 StandardCharsets
String str1 = new String(bytes, StandardCharsets.UTF_8);
System.out.println("使用 StandardCharsets.UTF_8: " + str1);
其他常用方法
String(byte[] bytes, Charset charset) (Java 7+)
这是 String(byte[] bytes, String charsetName) 的一个类型安全的版本,它直接接受一个 Charset 对象,而不是字符串,这可以避免运行时因编码名称无效而抛出 UnsupportedEncodingException 异常(在旧版本 Java 中)。
import java.nio.charset.StandardCharsets;
byte[] bytes = "Hello, World".getBytes(StandardCharsets.ISO_8859_1);
String str2 = new String(bytes, StandardCharsets.ISO_8859_1);
System.out.println("使用 Charset 对象: " + str2);
String(byte[] bytes, int offset, int length)
- 作用:从
byte数组的指定offset(偏移量)开始,取length个字节,使用默认编码进行转换。 - 缺点:同样有使用默认编码的问题,不推荐。
String(byte[] bytes, int offset, int length, String charsetName)
- 作用:从
byte数组的指定offset(偏移量)开始,取length个字节,使用指定的编码进行转换。 - 用途:当你只需要转换
byte数组中的一部分时使用。
import java.nio.charset.StandardCharsets;
byte[] allBytes = "这是一个测试字符串".getBytes(StandardCharsets.UTF_8);
int offset = 3; // 从第3个字节开始
int length = 6; // 取6个字节
String str3 = new String(allBytes, offset, length, StandardCharsets.UTF_8);
System.out.println("转换部分字节: " + str3); // 输出可能是 "个测"
完整示例代码
下面是一个完整的例子,演示了正确和错误的做法,以及不同编码的影响。

import java.nio.charset.StandardCharsets;
public class ByteToStringExample {
public static void main(String[] args) {
// 1. 准备一个UTF-8编码的字节数组
String originalStr = "你好,Hello";
byte[] utf8Bytes = originalStr.getBytes(StandardCharsets.UTF_8);
System.out.println("原始字符串: " + originalStr);
System.out.println("UTF-8 字节数组: " + java.util.Arrays.toString(utf8Bytes));
System.out.println("------------------------------------");
// 2. 推荐做法:明确指定编码
// 这是最安全、最可移植的方式
String strFromUtf8 = new String(utf8Bytes, StandardCharsets.UTF_8);
System.out.println("✅ 正确转换 (UTF-8): " + strFromUtf8);
// 3. 不推荐做法:使用平台默认编码
// 如果你的平台默认编码不是UTF-8,这里可能会乱码
try {
String strFromDefault = new String(utf8Bytes);
System.out.println("⚠️ 使用默认编码: " + strFromDefault);
} catch (Exception e) {
System.out.println("⚠️ 使用默认编码时发生错误或乱码。");
}
System.out.println("------------------------------------");
// 4. 演示错误编码导致的问题
// 假设数据是UTF-8格式,但你错误地用ISO-8859-1去解码
String wrongEncodingStr = new String(utf8Bytes, StandardCharsets.ISO_8859_1);
System.out.println("❌ 错误编码 (ISO-8859-1 解码 UTF-8): " + wrongEncodingStr);
// 输出会是乱码,"ä½ å¥½ï¼ŒHello"
// 5. 如何“修复”由错误编码导致的乱码?
// 如果你知道原始编码是UTF-8,但你用ISO-8859-1解码了,你可以这样做:
// 先用ISO-8859-1编码成字节,再用UTF-8解码回来
// (这通常只对单字节编码和UTF-8的兼容部分有效,但有时能救急)
byte[] intermediateBytes = wrongEncodingStr.getBytes(StandardCharsets.ISO_8859_1);
String fixedStr = new String(intermediateBytes, StandardCharsets.UTF_8);
System.out.println("🔧 尝试修复后: " + fixedStr);
}
}
运行结果分析:
- ✅ 正确转换 (UTF-8): 输出原始字符串
你好,Hello。 - ⚠️ 使用默认编码: 在大多数现代 Linux/macOS 环境下会正确,但在某些 Windows 默认编码为
GBK的环境下会乱码。 - ❌ 错误编码: 由于
ISO-8859-1无法表示中文字符,每个中文字符会被替换成一个 或其他不可读的字符,导致输出为乱码。 - 🔧 尝试修复后: 这是一个特殊的技巧,当你用
ISO-8859-1解码UTF-8字节时,它不会丢失任何字节信息(只是错误地解释了它们),所以你可以把“错误解释”后的字符串重新用ISO-8859-1编码回原来的字节,然后再用正确的UTF-8解码,从而恢复数据,但这是一种“应急”手段,最好的方法永远是一开始就用正确的编码。
总结与最佳实践
- 永远避免使用
new String(byte[]),因为它依赖于平台默认编码,是混乱的根源。 - 始终优先使用
new String(byte[], StandardCharsets.XXX),XXX是你明确知道的编码,如UTF_8,ISO_8859_1等。 UTF-8是现代应用的事实标准,除非有特殊的历史原因或与旧系统交互,否则请优先使用UTF-8。- 当处理从网络、文件或数据库读取的二进制数据时,务必清楚数据的原始编码是什么,协议或文件头会定义编码信息。
- 如果数据的来源你无法控制,且编码未知,这是一个非常棘手的问题,你可能需要尝试多种常见编码(如
UTF-8,GBK,ISO-8859-1)或者使用一些启发式算法来猜测编码,但这通常不可靠,最好的做法是让数据提供者明确告知编码。

