杰瑞科技汇

Java中string与byte如何高效转换?

  • 编码: 将 String (字符序列) 转换成 byte[] (字节序列) 的过程,你需要指定一种编码规则(如 UTF-8, GBK, ISO-8859-1)来决定每个字符应该用哪些字节表示。
  • 解码: 将 byte[] (字节序列) 转换成 String (字符序列) 的过程,你必须使用与编码时完全相同的编码规则,否则就会出现乱码。

下面我将详细讲解这两种转换,并提供最佳实践和常见陷阱。

Java中string与byte如何高效转换?-图1
(图片来源网络,侵删)

核心要点:始终指定字符编码

Java 中有 String.getBytes()new String(byte[]) 两个方法,它们都有一个“陷阱”。

String -> byte[] (编码)

不推荐的做法(使用平台默认编码)

String str = "你好,Java";
// 使用 JVM 默认字符集进行编码,不推荐!
// 在不同操作系统或环境下,默认编码可能不同(Windows 可能是 GBK,Linux/macOS 通常是 UTF-8)
byte[] bytesDefault = str.getBytes(); 

问题: 如果你的代码在 A 机器上(默认 UTF-8)运行,将 String 编码成 byte[],然后将这个 byte[] 发送到或保存到 B 机器上(默认 GBK),B 机器在解码时就会因为编码和解码使用的规则不一致而出现乱码。

推荐的做法(显式指定编码)

Java中string与byte如何高效转换?-图2
(图片来源网络,侵删)

你应该始终使用 String.getBytes(String charsetName) 方法,并明确指定一个标准、可靠的编码,首选 StandardCharsets.UTF_8

import java.nio.charset.StandardCharsets;
String str = "你好,Java";
// 推荐做法 1: 使用 StandardCharsets (Java 7+)
// 这是最清晰、最不容易出错的方式
byte[] bytesUtf8 = str.getBytes(StandardCharsets.UTF_8);
// 推荐做法 2: 使用字符集名称字符串
// 效果与上面相同,但需要处理 UnsupportedEncodingException(在 Java 7+ 中,如果传入的编码是标准的,这个异常理论上不会抛出)
// try {
//     byte[] bytesUtf8_2 = str.getBytes("UTF-8");
// } catch (UnsupportedEncodingException e) {
//     // 通常不会发生
// }

byte[] -> String (解码)

不推荐的做法(使用平台默认编码)

byte[] bytes = {-28, -67, -96, -27, -91, -67, -24, -81, -107, 74, 97, 118, 97}; // "你好,Java" 在 UTF-8 下的字节
// 使用 JVM 默认字符集进行解码,不推荐!
String strDefault = new String(bytes); 
// 如果你的默认编码不是 UTF-8,这里就会得到乱码,"浣犲ソJava"

推荐的做法(显式指定编码)

解码时,同样必须使用 new String(byte[], charset) 构造函数,并指定与编码时完全相同的编码。

Java中string与byte如何高效转换?-图3
(图片来源网络,侵删)
import java.nio.charset.StandardCharsets;
// 假设 bytes 是上面用 UTF-8 编码得到的字节数组
byte[] bytes = {-28, -67, -96, -27, -91, -67, -24, -81, -107, 74, 97, 118, 97}; 
// 推荐做法 1: 使用 StandardCharsets
String strUtf8 = new String(bytes, StandardCharsets.UTF_8);
System.out.println(strUtf8); // 输出: 你好,Java
// 推荐做法 2: 使用字符集名称字符串
try {
    String strUtf8_2 = new String(bytes, "UTF-8");
    System.out.println(strUtf8_2); // 输出: 你好,Java
} catch (UnsupportedEncodingException e) {
    // 通常不会发生
}

完整代码示例

下面是一个完整的、可运行的示例,展示了正确和错误的做法。

import java.nio.charset.StandardCharsets;
public class StringByteConversion {
    public static void main(String[] args) {
        // 1. String -> byte[] (编码)
        String originalStr = "这是一个测试 String。";
        // --- 推荐做法:显式指定 UTF-8 编码 ---
        byte[] encodedBytes = originalStr.getBytes(StandardCharsets.UTF_8);
        System.out.println("成功将 String 编码为 byte[] (使用 UTF-8)");
        System.out.println("原始字符串: " + originalStr);
        System.out.println("编码后的字节数组: " + java.util.Arrays.toString(encodedBytes));
        System.out.println("----------------------------------------");
        // --- 错误示范:使用默认编码 ---
        // 在一个默认编码不是 UTF-8 的环境中,这可能会导致问题
        byte[] encodedBytesDefault = originalStr.getBytes();
        System.out.println("使用默认编码将 String 编码为 byte[]");
        System.out.println("原始字符串: " + originalStr);
        System.out.println("编码后的字节数组: " + java.util.Arrays.toString(encodedBytesDefault));
        System.out.println("----------------------------------------");
        // 2. byte[] -> String (解码)
        // 我们使用上面正确编码得到的字节数组来演示
        // --- 推荐做法:使用相同的 UTF-8 解码 ---
        String decodedStr = new String(encodedBytes, StandardCharsets.UTF_8);
        System.out.println("成功将 byte[] 解码为 String (使用 UTF-8)");
        System.out.println("解码后的字符串: " + decodedStr);
        System.out.println("解码是否成功? " + originalStr.equals(decodedStr)); // true
        System.out.println("----------------------------------------");
        // --- 错误示范:解码时使用了错误的编码 ---
        // 假设我们错误地用 ISO-8859-1 (Latin-1) 来解码 UTF-8 的字节
        String wrongDecodedStr = new String(encodedBytes, java.nio.charset.StandardCharsets.ISO_8859_1);
        System.out.println("错误示范:用 ISO-8859-1 解码 UTF-8 字节");
        System.out.println("解码后的字符串 (乱码): " + wrongDecodedStr);
        System.out.println("解码是否成功? " + originalStr.equals(wrongDecodedStr)); // false
        System.out.println("----------------------------------------");
    }
}

常见字符编码

编码名称 描述 适用场景
UTF-8 强烈推荐,Unicode 的可变长度编码,可以表示全球几乎所有字符,向后兼容 ASCII。 Web 开发、文件存储、网络通信、数据库连接的首选标准。
GBK / GB2312 中国国家标准编码,主要用于简体中文。 处理一些旧的、仅包含简体中文的文件或系统,尤其是在中国大陆。
ISO-8859-1 (Latin-1) 单字节编码,只能表示西欧语言字符,一个重要特性是:它不会造成乱码,任何字节序列都能被它解码,但非 ASCII 字符会被显示为 。 有时用作一种“安全”的中间编码,或者在不涉及多语言文本的场景下。
Big5 繁体中文编码,主要在台湾、香港使用。 处理繁体中文相关的旧系统或文件。
  1. 永远不要依赖 JVM 的默认编码,它会使你的代码在不同环境下产生不可预测的行为。
  2. 编码和解码必须使用相同的字符集,这是避免乱码的唯一法则。
  3. 优先使用 StandardCharsets.UTF_8,对于现代应用,UTF-8 是事实上的标准,能最大程度地保证兼容性和正确性。
  4. byte[] 本身没有编码信息,它只是一堆字节,你必须通过外部约定(比如协议头、文件元数据)或者约定俗成的方式(默认就是 UTF-8)来知道它应该用哪种编码来解析。
分享:
扫描分享到社交APP
上一篇
下一篇