Java 是動態連結語言,class 文件中的常量池不僅存放字面量(int、String 等),還儲存符號引用:類/介面全限定名、欄位名與描述符、方法名與描述符。編譯期不解析具體記憶體地址,而是保留文本符號,由 JVM 載入階段動態解析——這是 Java 動態性的基石。
| 類型 | 標籤值 | 說明 |
|---|---|---|
| CONSTANT_Utf8 | 1 | UTF-8 編碼 Unicode 字串 |
| CONSTANT_Integer | 3 | int 常量 |
| CONSTANT_Float | 4 | float 常量 |
| CONSTANT_Long | 5 | long 常量(佔兩項) |
| CONSTANT_Double | 6 | double 常量(佔兩項) |
| CONSTANT_Class | 7 | 類/介面符號引用 |
| CONSTANT_String | 8 | String 字面量 |
| CONSTANT_Fieldref | 9 | 欄位符號引用 |
| CONSTANT_Methodref | 10 | 類方法符號引用 |
| CONSTANT_InterfaceMethodref | 11 | 介面方法符號引用 |
| CONSTANT_NameAndType | 12 | 名稱與類型符號引用 |
每項包含項頭(1 字節標籤)與項體(變長資料)。
// 常量池項體聯合體(所有項體大小一致,便於陣列索引)
union constantPoolEntryStruct {
struct { unsigned short classIndex; unsigned short nameTypeIndex; } method; // Fieldref/Methodref 共用
CLASS clazz; // CONSTANT_Class
INTERNED_STRING_INSTANCE String; // CONSTANT_String
cell *cache; // 快取指標(clazz 或 String)
cell integer; // Integer/Float
long length; // Long/Double
NameTypeKey nameTypeKey; // NameAndType
NameKey nameKey;
UString ustring; // Utf8
};
// 常量池結構
struct constantPoolStruct {
union constantPoolEntryStruct entries[1]; // 柔性陣列,實際長度 = 項數 + 1
};
entries[0] 不存實際項體,而是存項數量(即 constant_pool_count - 1)constant_pool_count 緊跟在計數值後,計數值本身算作第 0 項entries 陣列後緊跟一個字節陣列,長度 = 實際項數(constant_pool_count - 1),每字節對應一項的標籤值。因 union 不攜帶類型資訊,需靠此陣列識別項類型。
位於 kvm/vmcommon/src/loader.c:
tableSize = numberOfEntries + ((numberOfEntries + 3) >> 2)constantPoolEntryStruct 大小(4 字節),向上取整實現 4 字節對齊完成後將指標賦給 CurrentClass->constPool,類實例擁有完整運行時常量池。
KVM 作為早期嵌入式 JVM 參考實作,其常量池設計展現了資源受限環境下的極致優化智慧,值得現代虛擬機開發者研習。