下面我将从最基础到最推荐的用法,详细解释各种方法。

核心要点:字符编码
在 Java 中,String 内部使用 UTF-16 编码来存储字符,而 byte 数组本身只是一串原始的字节,它如何被解释成字符,完全取决于你使用的字符编码。
最重要的原则: 在转换时,必须明确指定字符编码(如 UTF-8, ISO-8859-1 等),如果使用系统默认编码,可能会导致程序在不同环境下产生不一致的结果。
使用 String 构造函数(不推荐)
这是最直接的方法,但也是最容易被误用的方法。
byte[] bytes = {72, 101, 108, 108, 111}; // "Hello" 的 UTF-8 编码
// 使用系统默认编码(不推荐!)
String str1 = new String(bytes);
System.out.println("默认编码: " + str1);
// 明确指定编码(推荐做法)
String str2 = new String(bytes, StandardCharsets.UTF_8);
System.out.println("UTF-8 编码: " + str2);
为什么不推荐使用无参构造函数?
new String(byte[]) 会使用 JVM 的平台默认字符编码,这个编码可能因操作系统、语言环境甚至 JVM 启动参数而异。

- 在中文 Windows 系统上,默认可能是
GBK。 - 在 macOS 或 Linux 上,默认可能是
UTF-8。
如果你的 byte 数组是用 UTF-8 编码的,但在一个默认 GBK 的系统上运行,转换出来的字符串就会是乱码。
何时使用?
只有在你能100%确定 byte 数组就是使用 JVM 的默认编码编码的,并且你的程序也只运行在这个环境下时,才考虑使用,否则,请始终指定编码。
使用 StandardCharsets(推荐)
这是 Java 7 引入的、最安全、最清晰、最高效的方法。StandardCharsets 类提供了一些常用编码的常量对象。
推荐用法:

import java.nio.charset.StandardCharsets;
public class ByteArrayToString {
public static void main(String[] args) {
// 1. 准备一个 byte 数组
// "你好,世界!" 的 UTF-8 编码
byte[] utf8Bytes = {-28, -72, -83, -27, -101, -98, -26, -107, -116, -25, -91, -119, -27, -107, -116, 33};
// 2. 使用 StandardCharsets.UTF_8 进行转换(最佳实践)
String strFromUtf8 = new String(utf8Bytes, StandardCharsets.UTF_8);
System.out.println("从 UTF-8 byte 数组转换: " + strFromUtf8);
// 3. 同样适用于其他标准编码,如 ISO-8859-1 (Latin-1)
byte[] latin1Bytes = {72, 101, 108, 108, 111}; // "Hello" 在 Latin-1 中和 ASCII 一样
String strFromLatin1 = new String(latin1Bytes, StandardCharsets.ISO_8859_1);
System.out.println("从 ISO-8859-1 byte 数组转换: " + strFromLatin1);
}
}
优点:
- 类型安全:编译器会检查你传入的
Charset是否有效,避免了拼写错误。 - 高效:
StandardCharsets中的常量是预定义的,避免了每次都去查找编码名称的性能开销。 - 清晰易读:代码意图非常明确。
使用 Charset.forName()(灵活但稍逊一筹)
如果你使用的字符编码不是 StandardCharsets 中预定义的(GBK, Big5 等),你可以使用 Charset.forName() 方法。
import java.nio.charset.Charset;
public class ByteArrayToStringWithCustomCharset {
public static void main(String[] args) {
// "你好" 的 GBK 编码
byte[] gbkBytes = {-60, -29, -70, -61};
// 使用 Charset.forName() 指定编码
String strFromGbk = new String(gbkBytes, Charset.forName("GBK"));
System.out.println("从 GBK byte 数组转换: " + strFromGbk);
// 也可以使用字符串字面量,但稍有不安全(拼写错误会导致运行时异常)
// String strFromGbk2 = new String(gbkBytes, "GBK");
// System.out.println("从 GBK byte 数组转换 (字符串): " + strFromGbk2);
}
}
优点:
- 灵活性高:可以支持任何 Java 虚拟机支持的字符编码。
缺点:
- 性能稍低:
Charset.forName()在每次调用时都需要进行查找和解析。 - 运行时异常:如果编码名称拼写错误(如 "UT-8" 而不是 "UTF-8"),会抛出
java.nio.charset.IllegalCharsetException,而StandardCharsets在编译时就能保证正确。
特殊情况:处理二进制数据(如图片、文件)
如果你的 byte 数组代表的是二进制数据(例如一张图片、一个 PDF 文件、一个加密后的文件),而不是用某种字符编码编码的文本,那么直接将其转换为 String 是错误的,这几乎一定会导致数据损坏和乱码。
在这种情况下,你不应该将其转换为 String,如果你需要以文本形式表示这些字节(用于日志或传输),通常的解决方案是使用Base64 编码。
正确做法:Base64 编码
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class ByteArrayToBase64String {
public static void main(String[] args) {
// 1. 准备一个二进制 byte 数组(一张小图片的字节数据)
byte[] binaryData = "This is some binary data, not text!".getBytes(StandardCharsets.UTF_8);
// 2. 使用 Base64 编码器将其转换为 String
Base64.Encoder encoder = Base64.getEncoder();
String base64String = encoder.encodeToString(binaryData);
System.out.println("Base64 编码后的字符串:");
System.out.println(base64String);
// 3. 如果需要,可以从 Base64 字符串解码回原始 byte 数组
Base64.Decoder decoder = Base64.getDecoder();
byte[] decodedData = decoder.decode(base64String);
System.out.println("\n解码后的 byte 数组内容:");
System.out.println(new String(decodedData, StandardCharsets.UTF_8));
}
}
Base64 的作用:
它将二进制数据转换为由 A-Z, a-z, 0-9, , 和 组成的 ASCII 字符串,这使得二进制数据可以安全地在只支持文本的协议(如 HTTP、XML、JSON)中传输。
总结与最佳实践
| 场景 | 推荐方法 | 示例代码 | 原因 |
|---|---|---|---|
| 将文本字节转为字符串 | StandardCharsets |
new String(bytes, StandardCharsets.UTF_8) |
最安全、最高效、最清晰,避免因环境不同导致的乱码。 |
| 使用非标准编码(如GBK) | Charset.forName() |
new String(bytes, Charset.forName("GBK")) |
灵活性高,能支持所有 JVM 编码,但要注意性能和异常。 |
| 处理二进制数据 | Base64 编码 | Base64.getEncoder().encodeToString(binaryData) |
绝对不要直接将二进制数据转为 String,应使用 Base64 等方案进行编码。 |
| 不推荐的做法 | 无参构造函数 | new String(bytes) |
依赖不确定的“默认编码”,极易导致跨平台乱码问题。 |
记住这个黄金法则:
永远不要在 Java 中使用
new String(byte[])不带编码参数的形式,始终明确指定字符编码。
