首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 字符編碼深度解析:從 class 文件到 JVM 運行時

     編輯:Java 相關知識

前言

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-8JVM 規範強制要求,節省空間
JVM 運行時 (char/String)UTF-16固定 2 字節 (BMP 字符),補充字符用 4 字節

驗證過程

1. .class 文件分析

public class Test { public static void main(String[] args) { String str = "張"; } }
  • javap -verbose Test.class 查看常量池
  • WinHex 打開 class 文件,確認常量池存儲為 E5 BC A0 (UTF-8)

2. 運行時驗證

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 字節)。

3. 源碼佐證

java.lang.Character 類內部編碼處理均基於 UTF-16,String 底層 char[] (Java 9+ 為 byte[] + coder) 同樣遵循此規範。

關鍵結論

  1. char 類型可存中文:BMP 範圍內字符 (含中日韓統一表意文字) 僅佔 1 個 char (2 字節)
  2. 補充字符需 2 個 char:如 Emoji (😀 U+1F600) 需用 char[2] (代理對) 表示
  3. 編碼轉換發生在 I/O 邊界:讀取文件/網絡時指定 Charset,JVM 內部統一 UTF-16

最佳實踐

  • 顯式指定 StandardCharsets.UTF_8 進行 I/O 操作
  • 避免使用平台默認編碼 (new String(bytes) 無參構造)
  • 處理補充字符時使用 codePoint 相關 API (codePointAt, codePointCount)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved