Java 為實現國際化,內部使用 Unicode 字符集存儲字符。但 Unicode 僅是字符集,具體存儲需具體編碼方案(UTF-8、UTF-16 等)。許多開發者混淆 Unicode 與 UTF-8,導致對 Java 內部編碼產生誤解。本文通過實驗驗證 Java 真實的內部編碼格式。
String name = "堂";
char c = name.charAt(0); // 單字符
int low = c & 0xff; // 低位字節
int high = (c >> 8) & 0xff; // 高位字節
System.out.println(Integer.toHexString(high) + " " + Integer.toHexString(low));
// 輸出: 58 02 (僅 2 字節 = 16 位)
結論:Java char 固定 16 位,非 UTF-8(UTF-8 為變長編碼,中文通常 3 字節)。
byte[] utf8 = name.getBytes("UTF-8");
printBytes(utf8);
// 輸出: e5 a0 82 length = 3 (3 字節,符合 UTF-8 中文編碼)
byte[] utf16 = name.getBytes("UTF-16");
printBytes(utf16);
// 輸出: fe ff 58 02 length = 4 (含 BOM 頭 2 字節)
去除 BOM 後低 16 位 58 02 與 char 內部值一致,說明內部編碼與 UTF-16 相關。
byte[] utf16be = name.getBytes("UTF-16BE");
printBytes(utf16be);
// 輸出: 58 02 length = 2 (完全匹配 char 內部值)
結論:Java 內部字符編碼為 UTF-16BE(大端序,無 BOM)。
public static void printBytes(byte[] bytes) {
for (byte b : bytes) {
System.out.print(Integer.toHexString(b & 0xff) + " ");
}
System.out.println(" length = " + bytes.length);
}
String.getBytes(charset) 會按指定編碼將內部 UTF-16BE 轉換為目標字節序列。new String(bytes, charset) 為逆向操作:按編碼解碼字節數組為內部 UTF-16BE。Java 內部採用 UTF-16BE 固定 16 位編碼存儲字符,而非 UTF-8。掌握此本質,結合 getBytes() / String 构造器 進行顯式編碼轉換,是解決中文亂碼問題的關鍵基石。