核心概念
我们需要明确几个术语:

(图片来源网络,侵删)
- UTF-8: 一种字符编码方案,它将 Unicode 字符(码点)表示为一个到四个字节的序列,它是目前互联网上使用最广泛的编码方式。
- Unicode 码点: 每个字符在 Unicode 字符集中的唯一编号,它是一个整数值,范围从
U+0000到U+10FFFF,在 Java 中,char类型(16位)可以表示大部分码点(BMP 平面),但对于增补平面的字符(如 Emoji "😂"),需要用int类型来表示完整的码点。 - Unicode 转义序列: Java 和许多其他语言中的一种表示法,用
\u后跟4位十六进制数来表示一个char范围内的字符。A可以写成\u0041。
你的问题“UTF8转unicode”通常指两种操作:
- 操作一:将 UTF-8 字节流解码成 Java 字符串(字符串内部由 Unicode 码点组成)。
- 操作二:将一个字符串中的每个字符转换成其对应的 Unicode 转义序列(
\uXXXX形式)。
下面我们分别讨论这两种操作。
将 UTF-8 字节数组解码为字符串(得到 Unicode 码点)
这是最常见的操作,当你从文件、网络或数据库中读取到一串 UTF-8 编码的字节数据时,你需要将它们转换成 Java 的 String 对象。String 对象内部就是以 UTF-16 编码存储 Unicode 码点的。
方法 1:使用 String 构造函数(最直接、推荐)
这是最简单直接的方法,Java 的 String 类提供了可以直接接受 byte[] 和字符集名称的构造函数。

(图片来源网络,侵删)
import java.nio.charset.StandardCharsets;
public class Utf8ToString {
public static void main(String[] args) {
// 示例:UTF-8 编码的字节序列
// "你好" 的 UTF-8 编码是 E4 BD A0 E5 A5 BD
// "😂" 的 UTF-8 编码是 F0 9F 98 82
byte[] utf8Bytes = {(byte) 0xE4, (byte) 0xBD, (byte) 0xA0, (byte) 0xE5, (byte) 0xA5, (byte) 0xBD, (byte) 0xF0, (byte) 0x9F, (byte) 0x98, (byte) 0x82};
// 使用 String 构造函数进行解码
// StandardCharsets.UTF8 是 Java 7 引入的,比 "UTF-8" 字符串更安全、高效
String str = new String(utf8Bytes, StandardCharsets.UTF_8);
System.out.println("解码后的字符串: " + str);
// 输出: 解码后的字符串: 你好😂
}
}
方法 2:使用 Charset 和 CharsetDecoder(更灵活、可控)
当你需要更精细地控制解码过程时(处理错误、替换无效字符),可以使用 java.nio.charset 包中的类。
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
public class Utf8DecoderExample {
public static void main(String[] args) throws CharacterCodingException {
byte[] utf8Bytes = {(byte) 0xE4, (byte) 0xBD, (byte) 0xA0, (byte) 0xE5, (byte) 0xA5, (byte) 0xBD};
// 1. 获取 UTF-8 的 Charset 对象
Charset charset = StandardCharsets.UTF_8;
// 2. 创建一个解码器
CharsetDecoder decoder = charset.newDecoder();
// 3. (可选) 配置解码器如何处理错误
// CodingErrorAction.REPLACE: 用替换字符('�')替换无法解码的输入
// CodingErrorAction.IGNORE: 忽略无法解码的输入
// CodingErrorAction.Report: 抛出 CharacterCodingException 异常
decoder.onMalformedInput(CodingErrorAction.REPLACE);
decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
// 4. 将字节数组包装到 ByteBuffer 中
ByteBuffer byteBuffer = ByteBuffer.wrap(utf8Bytes);
// 5. 解码
CharBuffer charBuffer = decoder.decode(byteBuffer);
// 6. 从 CharBuffer 获取字符串
String str = charBuffer.toString();
System.out.println("使用解码器得到的字符串: " + str);
// 输出: 使用解码器得到的字符串: 你好
}
}
将字符串转换为 Unicode 转义序列(\uXXXX)
这个需求是遍历字符串中的每个字符,并将其格式化为 \u 加上4位十六进制数的形式。
方法:手动遍历和格式化
这个操作没有内置的库方法,需要自己编写逻辑,核心是使用 Character 类的 getNumericValue 或直接转换 char 的整数值。
public class StringToUnicodeEscapes {
public static void main(String[] args) {
String str = "你好A";
System.out.println("原始字符串: " + str);
System.out.println("Unicode 转义序列: " + stringToUnicodeEscapes(str));
}
/**
* 将字符串转换为 Unicode 转义序列 (\uXXXX)
* 注意:此方法只处理 BMP 字符平面内的字符 (char 范围)。
* 对于增补平面的字符 (如 Emoji),会被拆分成两个 surrogates,各自转义。
*
* @param str 输入字符串
* @return Unicode 转义序列字符串
*/
public static String stringToUnicodeEscapes(String str) {
if (str == null) {
return null;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
// char c = str.charAt(i); // 对于增补平面字符,char 会得到一个 surrogate
// 使用 codePointAt 可以正确处理所有 Unicode 字符
int codePoint = str.codePointAt(i);
// 如果是增补平面的字符,codePoint 会大于 0xFFFF
// 这里我们将其转换为两个 surrogates,然后分别转义
if (codePoint > 0xFFFF) {
// 计算高位和低位 surrogate
int highSurrogate = Character.highSurrogate(codePoint);
int lowSurrogate = Character.lowSurrogate(codePoint);
sb.append(String.format("\\u%04x", highSurrogate));
sb.append(String.format("\\u%04x", lowSurrogate));
// 因为增补平面字符占用了两个 char 位置,i 需要向前移动一位
i += Character.charCount(codePoint) - 1;
} else {
// BMP 字符平面内的字符,直接转义
sb.append(String.format("\\u%04x", codePoint));
}
}
return sb.toString();
}
}
代码解释:

(图片来源网络,侵删)
str.codePointAt(i):这是获取字符完整 Unicode 码点的正确方法,尤其对于 Emoji 等增补平面字符。Character.charCount(codePoint):返回指定码点占用的char数量(1 或 2)。Character.highSurrogate(codePoint)和Character.lowSurrogate(codePoint):将一个增补平面的码点分解为两个代理项对(surrogate pair)。String.format("\\u%04x", codePoint):这是格式化的核心。%04x表示将整数格式化为4位、前面补零的十六进制字符串,第一个\用于转义第二个\。
输出结果:
原始字符串: 你好A
Unicode 转义序列: \u4f60\u597d\u0041
| 需求 | 推荐方法 | 核心代码 | 说明 |
|---|---|---|---|
| 将 UTF-8 字节数组解码为字符串 | String 构造函数 |
new String(byteArray, StandardCharsets.UTF_8); |
最常用、最简单的方法。 |
CharsetDecoder |
decoder.decode(ByteBuffer.wrap(byteArray)); |
更灵活,可用于处理编码错误。 | |
| 将字符串转换为 Unicode 转义序列 | 手动遍历和格式化 | String.format("\\u%04x", charValue) |
需要自己处理循环和逻辑,特别是对增补平面字符的处理。 |
希望这个详细的解释和代码示例能帮助你理解在 Java 中如何进行 UTF-8 和 Unicode 之间的转换!
