char 是 16 位类型,只能表示 bmp 平面(u+0000–u+ffff)字符;补充字符(u+10000–u+10ffff)需用代理对(两个 char)表示,故 char 无法直接表示。

Java 中 String.codePointAt(int index) 可以正确处理 Unicode 补充字符(即码点大于 0xFFFF 的字符),但前提是你要理解它操作的是“代码点”而非“char”,并配合 String.offsetByCodePoints 等方法使用,否则容易越界或跳过字符。
为什么 char 无法表示补充字符?
Java 的 char 是 16 位无符号整数,只能表示基本多文种平面(BMP)中的字符(U+0000 到 U+FFFF)。而补充字符(如大多数 emoji、古汉字、数学符号等)位于 U+10000 到 U+10FFFF 范围,需用两个 char(代理对:surrogate pair)表示:
- 高位代理(high surrogate):U+D800–U+DBFF
- 低位代理(low surrogate):U+DC00–U+DFFF
直接用 charAt(i) 获取某个位置的 char,可能只拿到代理对的一半,导致乱码或逻辑错误。
codePointAt 的正确用法
codePointAt(index) 返回指定索引处的**完整 Unicode 代码点**(int 类型),自动识别代理对。关键点是:索引必须指向代理对的**起始位置**(即高位代理所在位置)。
例如:
String s = "Hello\uD83D\uDE00\u2603"; // "Hello?❄" // \uD83D\uDE00 是 ? 的代理对,占两个 char 位置 System.out.println(s.codePointAt(5)); // 128512(? 的码点 U+1F600) System.out.println(s.codePointAt(6)); // ❌ 错误!6 是低位代理位置,返回的是 \uDE00(56320)本身
所以不能随意传入任意索引 —— 必须确保该索引对应一个“代码点的起始位置”。
安全遍历字符串的所有代码点
推荐用 String.codePoints()(Java 8+)流式遍历,或手动配合 Character.isSurrogatePair 和 offsetByCodePoints:
- ✅ 推荐方式(简洁安全):
s.codePoints().forEach(cp -> System.out.printf("U+%04X%n", cp)); - ✅ 手动循环(兼容旧版):
for (int i = 0; i int cp = s.codePointAt(i);<br> System.out.printf("U+%04X%n", cp);<br> i += Character.charCount(cp); // 自动跳过 1 或 2 个 char
Character.charCount(int codePoint) 会返回该码点占用的 char 数(1 或 2),比硬写 i++ 或 i += 2 更可靠。
获取补充字符的字符串表示
若你有一个码点(比如 0x1F600),想转成对应字符串:
- 用
String.valueOf(Character.toChars(codePoint))(推荐) - 或
new String(Character.toChars(codePoint))
不要用 (char)codePoint 强转 —— 对补充字符会截断,得到无效值。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











