深入理解Java虛擬機之.class文件的數據結構一


Class類文件的結構

無關性的基石

上圖是Java虛擬機實現語言無關性的生動描述。可以看出,Java虛擬機不和包括Java在內的任何語言綁定,它只與“Class文件“這種特定的二進制文件格式所關聯,Class文件中包含了Java虛擬機指令集和符號表以及若干其他輔助信息。基於安全性方面的考慮,Java虛擬機規范要求在Class文件中使用許多強制性的語法和結構化約束,但任一門功能性語言都可以表示為一個能被Java虛擬機所接受的有效的Class文件。作為一個通用的,機器無關性的執行平台,任何其他語言都可以將Java虛擬機作為語言的產品交付媒介。

Class類文件結構

Class文件是一組以8位字節為基礎單位的二進制流,各個數據項目嚴格按照順序緊湊地排列在Class文件之中,中間沒有添加任何分隔符,這使得整個Class文件中存儲地內容幾乎全部都是程序運行地必要數據,沒有空隙存在。當遇到需要占用8位字節以上空間地數據項時,則會按照高位在前地方式分割成若干個8位字節進行存儲。
根據Java虛擬機規范,Class文件格式采用一種類似於C語言結構體地偽結構體來存儲數據,這種偽結構體中只有兩種數據類型:無符號數和表

  • 無符號數

無符號數屬於基本數據類型,以u1、u2、u4、u8來分別代表1個字節、2個字節、4個字節和8個字節的無符號數,無符號數可以用來描述數字、索引引用、數量值或者按照UTF-8編碼構成字符串值。

表是由多個無符號數或者其他表作為數據項構成的復合數據類型,所有表都習慣性地以"_info”結尾。表用於描述有層次關系地復合結構地數據,整個Class文件本質上就是一張表。

上圖是Class文件的文件格式,無論是無符號數還是表,當需要描述同一類型但數量不定的多個數據時,經常會使用一個前置的容量計數器加若干個連續的數據項的形式,這時稱這一系列連續的某一類型的數據為某一類型的集合。

下面我們用一段Java代碼作為實例來認識Class文件

下圖是使用WinHex打開Class文件的結果。

1.魔數與Class文件的版本

Class文件的前4個字節稱為魔數(Magic Number),它是用來確定這個文件是否為一個Java虛擬機可以接受的Class文件;緊接着魔數的四個字節是Class文件的版本號(Major Version),第5個和第6個字節是次版本號(Minor Version),第7和第8個字節是主版本號(Major Version)(有關Java版本號的問題我們先略過),版本號是用來區別當前的Class文件是否可以被執行,通常的版本是向下兼容的。

2.常量池

緊接着主次版本號之后的是常量池入口,常量池可以理解為Class文件之中的資源倉庫,它是Class文件結構中與其他項目關聯最多的數據類型,也是占用Class文件空間最大的數據項目之一,同時它還是在Class文件中第一個出現的表類型數據項目。

由於常量池中常量的數量是不固定的,所以在常量池的入口需要放置一項u2類型的數據,代表常量池容量計數值(Constant_pool_count),與java語言不同的是,容量計數器是從1開始計數的,對於其他集合類型,包括接口索引集合、字段表集合、方法表集合等的容量計數都與一般習慣相同。

常量池放了什么?

常量池中主要存放兩大類常量,字面量(Literal)和符號引用(Symbolic References)。字面量比較接近Java語言層面的常量概念,如文本字符串、聲明為final的常量值等。而符號引用包括類和接口的全限定名、字段的名稱和描述符、方法的名稱和描述符這三類常量。

Java代碼在進行編譯的時候是進行動態鏈接的。在Class文件中不會保存各個方法、字段的最終內存布局信息,因此這些字段、方法的符號引用需要從常量池獲得對應的符號引用,再在類創建時或運行時解析,翻譯到具體的內存地址之中。

常量池中的每一項常量都是一張表,在JDK1.7中總計有14種表結構:

之所以說常量池是最煩瑣的數據,是因為這14種常量類型各自均有自己的結構。有關其中的類型請筆者查看書中第169頁的分析以及172頁的總表結構。

從圖中我們可以看出計算機已經幫我們把整個常量池中18項常量計算了出來。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM