JVM虛擬機-Class文件之常量池

一、常量池的作用

在class文件中的魔數、副版本號、主版本之後,緊接着就是常量池的數據區域了,如下圖用紅線包括的位置:

常量池可以比喻爲Class文件裏的資源倉庫,它是Class 文件結構中與其他項目關聯最多的數據,通常也是佔用Class文件空間最大的數據項目之一,另外,它還是在Class文件中第一個出現的表類型數據項目。

二、常量池的結構

常量池的結構比較簡單,前面的兩個字節叫做常量池計數器(constant_pool_count),它記錄了常量池項(cp_info)的個數。後面緊接着就是constant_pool_count-1常量池項(cp_info)。這跟報文通信協議比較類似,首先定義報文的大小,接着就是對應大小的報文內容。

由於常量池中常量的數量是不固定的,所以在常量池的入口需要放置一項u2類型的數據,代表常量池容量計數值(constant_pool_count)。與Java中語言習慣不同,這個容量計數是從1而不是0開始的,如上圖所示,常量池容量(偏移地址:0x00000008)爲十六進制數0x0021,即十進制的33,這就代表常量池中有33項常量,索引值範圍爲1~33。在Class文件格式規範制定之時,設計者將第0項常量空出來是有特殊考慮的,這樣做的目的在於,如果後面某些指向常量池的索引值的數據在特定情況下需要表達“不引用任何一個常量池項目”的含義,可以把索引值設置爲0來表示。Class文件結構中只有常量池的容量計數是從1開始,對於其他集合類型,包括接口索引集合、字段表集合、方法表集合等的容量計數都與一般習慣相同,是從0開始。

三、常量池的分類

常量池中主要存放兩大類常量:字面量(Literal)和符號引用(Symbolic References)。字面量比較接近於Java語言層面的常量概念,如文本字符串、被聲明爲final的常量值等;而符號引用則屬於編譯原理方面的概念。具體分類如下圖:

常量池中每一項常量都是一個表,最初常量表中共有11種結構各不相同的表結構數據,後來爲了更好地支持動態語言調用,額外增加了4種動態語言相關的常量,爲了支持Java模塊化系統 (Jigsaw),又加入了CONSTANT_M odule_info和CONSTANT_Package_info兩個常量,所以截至JDK 13,常量表中分別有17種不同類型的常量。這17類表都有一個共同的特點,表結構起始的第一位是個u1類型的標誌位(tag,取值見下表中標誌列),代表着當前常量屬於哪種常量類型。

官網最新:http://cr.openjdk.java.net/~jrose/jvm/constant-dynamic-jrose.html

我們對這個class文件進行分析,可以看到前8個字節是該class文件的魔數和版本號,緊接着的一個十六進制數0x0021,即十進制的33,這就代表z這個class文件的常量池中有32項常量,索引值爲1~32。然後就是第一個常量了,上面說過,每種類型的常量開始的第一位都是一個u1類型的標誌位,代表該常量的類型,這裏是0x0a,十進制的10,查上面的表可知是CONSTANT_Methodref_info,說明這個常量是類中方法的符號應用。該類型常量的具體結構爲:

第一個index值爲0x0004,即指向常量池中的第4個常量,第二個index是0x0019,即指向常量池中的第25個常量。在JDK的bin目錄中,Oracle公司已經爲我們準備好一個專門用於分析Class文件字節碼的工具:javap。我們可以用javap -verbose命令查看class文件的字節碼內容。

可以看到和我們分析的一致,該class文件中確實有32項常量,從#1到#32。

四、17種數據類型結構總表

參考資料:

  1. https://blog.csdn.net/wangtaomtk/article/details/52267548
  2. https://blog.csdn.net/cold___play/article/details/105325698
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章