Java 聲稱原生支援 Unicode,但直到 JDK 5.0 才真正完整支援補充字元。本文深入解析 Unicode 碼空間劃分、BMP 與補充平面、Surrogate Pair 編碼機制、Code Point 與 Code Unit 差異,並提供實際代碼驗證。
JDK 5.0+ 使用 兩個 char 組成 Surrogate Pair 表示補充字元:
int (32-bit) 儲存U+D800 ~ U+DFFF (2,048 碼位) 保留給 Surrogate Pair 機制,Unicode 標準與 UTF-16 皆不分配字元 至此區間。此設計使 BMP 字元與單一 char UTF-16 編碼一一對應。
| 概念 | 定義 | 範例 |
|---|---|---|
| Code Point | Unicode 分配給字元的唯一編號 | "漢" = U+6C49 |
| Code Unit | 編碼方案中字元的最小儲存單元 | UTF-16: 1 char (2 bytes) UTF-8: 1 byte 補充字元 UTF-16: 2 char |
一個字元 = 一個 Code Point,但可能佔多個 Code Unit。統一使用 Code Point 指定字元可避免編碼轉換困擾。
String s = String.valueOf(Character.toChars(0x2F81A));
char[] chars = s.toCharArray();
for (char c : chars) {
System.out.format("%x ", (short) c);
}
// 輸出: d87e dc1a
// d87e = High Surrogate, dc1a = Low Surrogate
| 需求 | 正確方法 | 錯誤做法 |
|---|---|---|
| 取得字串長度 (字元數) | str.codePointCount(0, str.length()) | str.length() (回傳 char 數) |
| 遍歷每個字元 | str.codePoints().forEach(cp -> ...) | for (char c : str.toCharArray()) |
| 指定補充字元 | Character.toChars(codePoint) | 直接寫入 char 常值 |
| 檢查是否為補充字元 | Character.isSupplementaryCodePoint(cp) | cp > 0xFFFF |
String.length() 回傳 char 數,補充字元算 2,非直觀字元數substring、charAt 以 char 索引操作,可能切斷 Surrogate Pairutf8mb4)\x{1F600} 語法匹配補充字元 (需 Pattern.UNICODE_CHARACTER_CLASS)理解 Code Point/Code Unit 差異、Surrogate Pair 機制與正確 API 使用,是處理多語言、Emoji、罕見漢字等現代應用的基礎能力。