杰瑞科技汇

Java如何将UTF-8转为Unicode?

UTF-8 Unicode 的一种实现方式(编码方案)。

Java如何将UTF-8转为Unicode?-图1
(图片来源网络,侵删)

你问的“UTF-8 转 Unicode”在 Java 中通常指的是以下两种情况:

  1. 将 UTF-8 编码的 byte[]String 转换成 Java 内部使用的 char 数组或 String 对象。 这是最常见的需求。
  2. 将 UTF-8 编码的字符转换成它的 Unicode 码点(整数表示)。

下面我将详细解释这两种情况,并提供完整的代码示例。


核心概念

  • Unicode: 这是一个字符集,它为世界上几乎所有的字符都分配了一个唯一的数字,这个数字被称为码点,字符 'A' 的码点是 U+0041,汉字 '中' 的码点是 U+4E2D,你可以把 Unicode 看作一本巨大的“字符编号字典”。
  • UTF-8: 这是一种将 Unicode 码点转换成计算机可以存储和传输的字节序列的规则,它是 Unicode 最流行的一种编码方式,它的特点是:
    • 兼容 ASCII。
    • 变长编码:常用字符(如英文字母)占用 1 个字节,非拉丁字符(如中文)通常占用 3 个字节。
  • Java String: 在 Java 中,String 对象内部使用 UTF-16 编码来存储字符,每个 char 通常代表一个 16 位的代码单元,对于大部分常见的 Unicode 字符(基本多语言平面 BMP),一个 char 就足够表示一个字符的码点,但对于一些特殊的辅助字符(如 Emoji 😊),需要两个 char(一个代理对)来表示。

当我们将一个 UTF-8 编码的字节数组转换成 Java String 时,Java 虚拟机会负责将 UTF-8 的字节序列解码成内部的 UTF-16 char 数组。


将 UTF-8 字节序列转换为 Java String (最常用)

这是最普遍的场景,比如你从网络、文件或数据库中读取了一段以 UTF-8 编码的字节数据,需要将其转换成一个可操作的 String 对象。

Java如何将UTF-8转为Unicode?-图2
(图片来源网络,侵删)

方法 1:使用 String 构造函数 (最直接)

String 类有一个专门接受 byte[] 和字符集名称的构造函数,它会自动帮你完成从指定编码(如 UTF-8)到内部 UTF-16 编码的转换。

import java.nio.charset.StandardCharsets;
public class Utf8ToString {
    public static void main(String[] args) {
        // 1. 准备一个 UTF-8 编码的字节数组
        // "Hello" -> 48 65 6C 6C 6F (ASCII, 1字节/字符)
        // "世界" -> E4 B8 96 E7 95 8C (中文, 3字节/字符)
        byte[] utf8Bytes = "Hello世界".getBytes(StandardCharsets.UTF_8);
        System.out.println("原始 UTF-8 字节数组: " + bytesToHex(utf8Bytes));
        // 输出: 原始 UTF-8 字节数组: 48656C6C6FE4B896E7958C
        // 2. 使用 String 构造函数将 byte[] 转换为 String
        // 指定字符集为 StandardCharsets.UTF_8 是最安全、最推荐的方式
        String decodedString = new String(utf8Bytes, StandardCharsets.UTF_8);
        System.out.println("解码后的 String: " + decodedString);
        // 输出: 解码后的 String: Hello世界
    }
    // 一个辅助方法,用于将字节数组打印成十六进制字符串,方便查看
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X ", b));
        }
        return sb.toString().trim().replace(" ", "");
    }
}

代码解释:

  1. "Hello世界".getBytes(StandardCharsets.UTF_8): 我们先创建一个 String,然后使用 StandardCharsets.UTF_8(这是一个预定义的、线程安全的 Charset 对象)将其编码成 UTF-8 字节数组,这模拟了从外部源获取字节数据的场景。
  2. new String(utf8Bytes, StandardCharsets.UTF_8): 这是核心步骤,我们调用 String 的构造函数,告诉 JVM:“utf8Bytes 这个数组是用 UTF-8 编码的,请把它按照这个规则解码成内部的 String 对象。”
  3. 为什么不直接用 new String(utf8Bytes) 如果不指定字符集,JVM 会使用平台的默认字符集,这在不同环境下(如 Windows 默认是 GBK,Linux 默认通常是 UTF-8)会导致乱码,是程序不稳定和 Bug 的主要来源之一。始终显式指定字符集!

方法 2:使用 Charset

这种方法与方法 1 类似,但更灵活,特别是当你需要复用 Charset 对象时。

import java.nio.charset.Charset;
public class Utf8ToStringWithCharset {
    public static void main(String[] args) {
        byte[] utf8Bytes = "Hello世界".getBytes(Charset.forName("UTF-8"));
        // 创建一个 UTF-8 的 Charset 对象
        Charset utf8Charset = Charset.forName("UTF-8");
        // 使用 Charset 对象进行解码
        String decodedString = new String(utf8Bytes, utf8Charset);
        System.out.println("解码后的 String: " + decodedString);
        // 输出: 解码后的 String: Hello世界
    }
}

StandardCharsets.UTF_8 本质上就是 Charset.forName("UTF-8") 的一个常量,使用前者可以避免在运行时进行字符串查找,性能略好且代码更清晰。

Java如何将UTF-8转为Unicode?-图3
(图片来源网络,侵删)

获取字符的 Unicode 码点

如果你不想要 String 对象,而是想得到字符对应的 Unicode 编号(码点),可以使用 String.codePointAt() 方法。

public class Utf8ToCodePoint {
    public static void main(String[] args) {
        String str = "A中😊"; // 包含一个拉丁字母,一个汉字,一个Emoji
        // codePointAt() 接受一个 index,返回该位置字符的码点
        // 注意:Emoji '😊' 是一个辅助字符,在 String 内部由两个 char 组成
        // '😊' 的 UTF-16 代理对是 \uD83D\uDE0A
        System.out.println("字符 'A' 的码点: " + str.codePointAt(0)); // 输出: 65 (U+0041)
        System.out.println("字符 '中' 的码点: " + str.codePointAt(1)); // 输出: 20013 (U+4E2D)
        System.out.println("字符 '😊' 的码点: " + str.codePointAt(2)); // 输出: 128515 (U+1F60A)
        // 将码点格式化为标准的 Unicode 表示法 (U+XXXX)
        System.out.println("'😊' 的码点 (U+格式): " + String.format("U+%04X", str.codePointAt(2)));
        // 输出: '😊' 的码点 (U+格式): U+1F60A
    }
}

重要提示:

  • str.charAt(index) 返回的是 char 类型,它无法正确表示像 '😊' 这样的辅助字符,只会返回代理对中的第一个 char (\uD83D)。
  • str.codePointAt(index) 是处理所有 Unicode 字符(包括辅助字符)的正确方式,它返回一个 int 类型的完整码点。

反向操作:String 转 UTF-8 字节序列

为了完整性,这里也提一下反向操作,即如何将 Java String 编码成 UTF-8 字节数组。

import java.nio.charset.StandardCharsets;
public class StringToUtf8 {
    public static void main(String[] args) {
        String originalString = "Hello世界";
        // 使用 getBytes 方法将 String 编码为 UTF-8 字节数组
        byte[] utf8Bytes = originalString.getBytes(StandardCharsets.UTF_8);
        System.out.println("原始 String: " + originalString);
        System.out.println("转换后的 UTF-8 字节数组: " + bytesToHex(utf8Bytes));
        // 输出: 转换后的 UTF-8 字节数组: 48656C6C6FE4B896E7958C
    }
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X ", b));
        }
        return sb.toString().trim().replace(" ", "");
    }
}
目标操作 核心方法/代码 关键点
UTF-8 byte[] -> String new String(byteArray, StandardCharsets.UTF_8) 必须显式指定字符集,否则依赖平台默认字符集,极易乱码。
String -> UTF-8 byte[] string.getBytes(StandardCharsets.UTF_8) 同样,显式指定字符集是最佳实践。
获取字符的 Unicode 码点 string.codePointAt(index) 返回 int 类型,能正确处理所有 Unicode 字符,包括 Emoji 等辅助字符。
获取字符的 UTF-16 代码单元 string.charAt(index) 返回 char 类型,对于辅助字符会返回不完整的代理对,不推荐用于通用处理

希望这个详细的解释和示例能帮助你彻底理解在 Java 中如何进行 UTF-8 和 Unicode 的转换!

分享:
扫描分享到社交APP
上一篇
下一篇