準備
class文件是Java虛擬機唯一可以識別的文件,根據Class文件我們可以完成一個程序的運行,本節文章是本人解析一個基本Class文件的全過程,記錄在此,希望能提供給正在前進路上的同學作為輔助作用,下面是我們要解析Class文件必要條件。
代碼
以下是一個簡單的Java類,一個私有變量,一個公開方法。
public class TestClass {
private int a;
public int increment() {
return a + 1;
}
}
將這個類編譯為Class文件
準備文本編輯器
本人使用Sublime Text打開我們編譯後的Class文件,主要目的是對照《Java虛擬機規範》中的Class文件的數據結構,下面是Sublime Text下載的網址。
Sublime Text
使用Sumlime打開Clas文件
《Java虛擬機規範》
我們需要按照Java虛擬機規範中的數據結構,進行Class文件的十六進制碼進行解析,所以這裏需要按照官網,進行解析,以下是PDF在線鏈接,本節使用Java8版本。
Java虛擬機規範1.8
打開《Java虛擬機規範》
解析
我們需要知道一個Class文件由哪些數據結構組成,並排列出來,一項數據佔幾個字節,這些我們都要知道。
我們首先需要記錄,這個Class文件的大體結構,Class文件的數據結構及順序都是需要嚴格按照《Java虛擬機規範》生成的,找到《Java虛擬機規範》中的 "The Class File Format (Class文件格式)"中的Class結構項。
需要解釋的是,這個ClassFile數據結構中的U2、u4分別代表兩個字節、四個字節,其對應的右邊的英文項,代表着其數據的常量項,Class文件是一定按照這個結構進行構件的,《Java虛擬機規範》中也説明了每一項的描述,本人結合官網整理如下:
這個是本人整理的Class文件的數據結構,有且只有這16項,具體的每一項,本文稍後都有解釋。其實Class文件並不複雜,只是Class中的引用比較多,例如constant_pool_info中,這是一個常量池,池中記錄着類、方法、字面量等描述符,是相互引用的方式。
javap查看class文件具體結構
使用javap查看文件結構,主要是為了供我們於Class二進制方式進行比對時的一個參照物,以説明我們解讀class文件時得出的結論是正確的。其餘我們需要確定我們常量池中的順序以及所對應的常量池名。
javap -v TestClass.class
輸出結果
根據javap所輸出的數據結構,我們得到了大致的數據結構,剩下的我們需要自行解析,並比對class中的十六進制數進行填寫。這裏採用yaml文本格式進行填充,yaml格式能很直觀的展現出一個對象的數據結構,並且採用這種方式也可以很直接的將解析的值帶入。針對我們要解析的class文件,其中____是我們要填充的數據,並且也進行了簡單的註釋説明字段的含義及所佔用的字節。結構如下:
class:
#魔數 u4
magic-number: ____
#小版本號 u2
minor-version: ____
#大版本號 u2
major-version: ____
#常量池
constant-pool:
#常量池總數 u2
count: ____
#常量池(數組)
constants: ____
#訪問標誌 u2
access_flags: ____
#當前類 u2
this_class: ____
#父類 u2
super_class: ____
#接口
interface:
# u2
count: ____
interfaces:
#字段
field:
# u2
count: ____
fields: ____
#方法
method:
# u2
count: ____
methods: ____
#屬性
attributes:
#u2
count: ____
attributes: ____
有了大致的結構,我們就可以開始解析之路啦!!
魔數
魔數項提供標識類文件格式的魔術數;它的值為0xCAFEBABE,這個值是固定的,每個文件都有屬於自己的魔數,但在class文件中,CAFEBABE就是class文件的魔數,它佔用4個字節。
隨後將CAFEBABE填入我們的yaml文件中:
小版本號
小版本號佔用2個字節,因此,將class文件中的0000轉換為十進制為0,所以小版本號為0;
大版本號
。。。