codepointat() 能正确处理 unicode 补充字符,因其自动识别代理对并返回完整码点;而 charat() 仅返回单个 16 位 char,会将 emoji 等拆分为无意义代理值,导致乱码、长度误判等问题。

Java 中 Character.codePointAt() 是处理 Unicode 补充字符(如大多数 Emoji、某些汉字、数学符号等)的关键方法,它能正确返回一个完整字符的码点(int 值),避免传统 charAt() 在代理对(surrogate pair)上出错。
为什么不能只用 charAt()?
Java 的 char 类型是 16 位,只能表示基本多文种平面(BMP)内的字符(U+0000–U+FFFF)。而很多 Emoji(如 ?、??、?)和部分汉字(如 ?)位于辅助平面(U+10000 及以上),需用两个 char(高代理 + 低代理)组合表示——即“代理对”。charAt() 每次只取一个 char,会把一个 Emoji 拆成两个无意义的代理值,导致长度误判、遍历错位、截断乱码等问题。
codePointAt() 的正确用法
该方法接收字符串和起始索引,返回对应位置的完整 Unicode 码点(int)。关键在于:它自动识别代理对,并跳过第二个代理字符。
- 调用时传入当前索引(如
i),它会检查str.charAt(i)是否为高代理;若是,且i+1存在且为低代理,则合并返回四字节码点 - 返回值范围是
0x0000–0x10FFFF,涵盖全部合法 Unicode 字符 - 需配合
Character.charCount(int codePoint)判断该码点占几个char位置(1 或 2),用于安全推进索引
安全遍历含 Emoji 的字符串
不要用 for (int i = 0; i 配 <code>charAt(),而应按码点步进:
String s = "Hello ???!"; for (int i = 0; i <p>这样每轮循环都拿到一个完整字符(哪怕它是 ??? 这类带 ZWJ 的组合 Emoji),不会切开代理对或打断修饰序列。</p> <h3>注意组合字符与变体选择符</h3> <p><code>codePointAt()</code> 能正确提取单个码点,但无法自动解析“字符序列”语义。例如:</p>
-
"??"是基础人形 + 皮肤修饰符(U+1F468 U+1F3FB),需两次codePointAt()调用分别获取 -
"??"是带 ZWJ 的组合(U+1F468 U+200D U+1F4BB),也是多个独立码点,codePointAt()仍逐个返回,不合并渲染效果
若需按“用户感知字符”(grapheme cluster)切分(如光标移动、编辑操作),需借助 ICU4J 或 Java 15+ 的 java.text.BreakIterator.getCharacterInstance(),而非仅靠 codePointAt()。
它解决的是底层码点精度问题,不是高级文本渲染逻辑。用对了,Emoji 就不会“断腿”或“消失”。










