Java 中 char 類型佔 2 字節,能否存儲中文?類文件與運行時編碼是否一致?本文通過實驗與源碼分析,徹底揭開 Java 字符編碼的謎底。
public class EncodingTest {
public static String getBytesHex(String content, String charset) throws Exception {
byte[] bytes = content.getBytes(charset);
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X ", b & 0xFF));
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
System.out.println("GBK: " + getBytesHex("張", "GBK")); // D5 C5
System.out.println("GB2312: " + getBytesHex("張", "GB2312")); // D5 C5
System.out.println("ISO-8859-1:" + getBytesHex("張", "ISO-8859-1")); // 3F (?)
System.out.println("Unicode: " + getBytesHex("張", "Unicode")); // FE FF 5F 20
System.out.println("UTF-16: " + getBytesHex("張", "UTF-16")); // FE FF 5F 20
System.out.println("UTF-8: " + getBytesHex("張", "UTF-8")); // E5 BC A0
}
}
| 階段 | 編碼格式 | 說明 |
|---|---|---|
| .class 文件常量池 | UTF-8 | JVM 規範強制要求,節省空間 |
| JVM 運行時 (char/String) | UTF-16 | 固定 2 字節 (BMP 字符),補充字符用 4 字節 |
public class Test { public static void main(String[] args) { String str = "張"; } }
javap -verbose Test.class 查看常量池WinHex 打開 class 文件,確認常量池存儲為 E5 BC A0 (UTF-8)public class RuntimeTest {
public static void main(String[] args) {
String str = "張";
// codePointAt 返回 Unicode 碼點
System.out.println(Integer.toHexString(str.codePointAt(0)).toUpperCase()); // 5F20
}
}
結果 5F20 即 Unicode 碼點,證明 JVM 內部使用 UTF-16 存儲 (BMP 字符佔 2 字節)。
java.lang.Character 類內部編碼處理均基於 UTF-16,String 底層 char[] (Java 9+ 為 byte[] + coder) 同樣遵循此規範。
char (2 字節)char[2] (代理對) 表示StandardCharsets.UTF_8 進行 I/O 操作new String(bytes) 無參構造)codePoint 相關 API (codePointAt, codePointCount)