杰瑞科技汇

Java字符串如何转byte数组?

核心要点:字符编码

Java 字符串内部使用 UTF-16 编码,当你将其转换为 byte[] 时,你必须选择一种字符编码方案(如 UTF-8, ISO-8859-1, GBK 等)来将字符序列映射到字节序列。

Java字符串如何转byte数组?-图1
(图片来源网络,侵删)

强烈建议始终使用 StandardCharsets.UTF_8,除非你有特殊需求。 UTF-8 是目前互联网上最通用的编码,它可以表示地球上几乎所有的字符,并且向后兼容 ASCII。


使用 String.getBytes()(不推荐,易出错)

这是最直接的方法,但它的行为取决于 JVM 的默认平台编码,不同的操作系统、不同的 JVM 配置,默认编码可能不同(Windows 可能是 GBK,而 Linux/macOS 通常是 UTF-8)。

语法:

byte[] bytes = str.getBytes();

问题示例:

Java字符串如何转byte数组?-图2
(图片来源网络,侵删)
String str = "你好,世界!";
// 在默认编码为 GBK 的 JVM 上运行
byte[] bytes = str.getBytes(); // 使用默认编码 GBK
// 在默认编码为 UTF-8 的 JVM 上运行
// byte[] bytes = str.getBytes(); // 使用默认编码 UTF-8
// 如果你在 GBK 环境下生成了 bytes,然后尝试用 UTF-8 去解码,就会得到乱码
String wrongStr = new String(bytes, StandardCharsets.UTF_8);
System.out.println(wrongStr); // 输出可能为:浣犲ソ锛屾垨闈�锛�

这种方法会导致代码在不同环境下产生不一致的结果,应尽量避免使用


使用 String.getBytes(StandardCharsets)(推荐)

这是最安全、最推荐的方法,你显式地指定了编码,使得代码在任何平台上行为都一致。StandardCharsets 是 Java 7 引入的枚举类,包含了最常用的几种编码常量。

使用 UTF-8 编码(最常用)

UTF-8 是一种可变长编码,ASCII 字符占 1 个字节,非 ASCII 字符(如中文)通常占 3 个字节,它是 Web 开发和数据交换的事实标准。

import java.nio.charset.StandardCharsets;
public class StringToBytesExample {
    public static void main(String[] args) {
        String str = "Hello, 世界!";
        // 使用 UTF-8 编码将字符串转换为 byte[]
        byte[] utf8Bytes = str.getBytes(StandardCharsets.UTF_8);
        System.out.println("原始字符串: " + str);
        System.out.println("UTF-8 字节数组: " + java.util.Arrays.toString(utf8Bytes));
        System.out.println("字节数组长度: " + utf8Bytes.length); // H(1) e(1) ... (3) 世(3) 界(3) !(1) = 1+1+1+1+1+3+3+1 = 12
        // 验证:从字节数组再转回字符串
        String decodedStr = new String(utf8Bytes, StandardCharsets.UTF_8);
        System.out.println("解码后的字符串: " + decodedStr); // 应该和原始字符串一致
    }
}

输出:

Java字符串如何转byte数组?-图3
(图片来源网络,侵删)
原始字符串: Hello, 世界!
UTF-8 字节数组: [72, 101, 108, 108, 111, 44, 32, -28, -72, -83, -27, -101, -67, 33]
字节数组长度: 12
解码后的字符串: Hello, 世界!

使用其他编码

根据你的需求,你也可以使用其他编码,ISO-8859-1(也叫 Latin-1)。

ISO-8859-1 的特点:

  • 它是一种单字节编码,每个字符固定占 1 个字节。
  • 它无法表示中文字符,所有非 ASCII 字符都会被替换为 。
  • 一个非常重要的特性是:它是一种“无损”的编码转换,也就是说,byte[] -> ISO-8859-1 String -> byte[] 的过程是双向可逆的,不会丢失任何信息,这使得它有时被用作一种“二进制数据的字符串表示”的中间格式。
import java.nio.charset.StandardCharsets;
public class StringToBytesExample_ISO {
    public static void main(String[] args) {
        String str = "Hello, 世界!";
        // 使用 ISO-8859-1 编码
        byte[] isoBytes = str.getBytes(StandardCharsets.ISO_8859_1);
        System.out.println("原始字符串: " + str);
        System.out.println("ISO-8859-1 字节数组: " + java.util.Arrays.toString(isoBytes));
        System.out.println("字节数组长度: " + isoBytes.length); // 所有字符都占 1 个字节,长度为 10
        // 验证:从字节数组再转回字符串
        String decodedStr = new String(isoBytes, StandardCharsets.ISO_8859_1);
        System.out.println("解码后的字符串: " + decodedStr); // 中文字符会丢失,变成问号
    }
}

输出:

原始字符串: Hello, 世界!
ISO-8859-1 字节数组: [72, 101, 108, 108, 111, 44, 32, 63, 63, 33]
字节数组长度: 10
解码后的字符串: Hello, ?!?

使用 String.getBytes(String charsetName)(较旧)

在 Java 7 之前,没有 StandardCharsets,人们通常使用这个方法,通过传入一个编码名称的字符串(如 "UTF-8")来指定编码。

语法:

byte[] bytes = str.getBytes("UTF-8");

缺点:

  • 如果传入的编码名称无效,会抛出 UnsupportedEncodingException,需要你 try-catch 处理。
  • 字符串形式的编码名不如 StandardCharsets 枚举类型安全(编译器无法检查)。
import java.io.UnsupportedEncodingException;
public class StringToBytesExample_Old {
    public static void main(String[] args) {
        String str = "Hello, 世界!";
        try {
            // 使用旧的指定编码名称的方式
            byte[] bytes = str.getBytes("UTF-8");
            System.out.println("字节数组: " + java.util.Arrays.toString(bytes));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}

如果你的代码可以运行在 Java 7 或更高版本,优先使用 StandardCharsets,因为它更简洁、更安全。


总结与最佳实践

方法 语法 优点 缺点 推荐度
默认编码 str.getBytes() 简单 依赖平台,不可预测,易导致乱码 ⭐ (不推荐)
推荐方式 str.getBytes(StandardCharsets.UTF_8) 安全、跨平台、明确、不抛出异常 ⭐⭐⭐⭐⭐ (强烈推荐)
旧版方式 str.getBytes("UTF-8") 可指定编码 需要处理 UnsupportedEncodingException ⭐⭐ (仅在旧Java项目中使用)
特殊场景 str.getBytes(StandardCharsets.ISO_8859_1) 单字节,可逆,适合处理二进制数据 无法表示多字节字符(如中文) ⭐⭐ (特定场景使用)

最佳实践:

  1. 默认使用 UTF-8: 在绝大多数情况下,使用 String.getBytes(StandardCharsets.UTF_8) 是你的首选。
  2. 明确编码: 在代码中始终显式地指定编码,不要依赖任何默认值。
  3. 处理二进制数据: 如果你需要将字节数组视为一个“不可打印”的二进制流,并且希望它能被 String 安全地“包装”和“解包”(在网络传输中),使用 StandardCharsets.ISO_8859_1 是一个巧妙的技巧,因为它保证了 byte[]String 之间的无损转换。
分享:
扫描分享到社交APP
上一篇
下一篇