博客 / 詳情

返回

JVM-解析Class文件示例

準備

class文件是Java虛擬機唯一可以識別的文件,根據Class文件我們可以完成一個程序的運行,本節文章是本人解析一個基本Class文件的全過程,記錄在此,希望能提供給正在前進路上的同學作為輔助作用,下面是我們要解析Class文件必要條件。

代碼

以下是一個簡單的Java類,一個私有變量,一個公開方法。

public class TestClass {

    private int a;

    public int increment() {

        return a + 1;
    }

}

將這個類編譯為Class文件

image.png

準備文本編輯器

本人使用Sublime Text打開我們編譯後的Class文件,主要目的是對照《Java虛擬機規範》中的Class文件的數據結構,下面是Sublime Text下載的網址。

Sublime Text

使用Sumlime打開Clas文件

image.png

《Java虛擬機規範》

我們需要按照Java虛擬機規範中的數據結構,進行Class文件的十六進制碼進行解析,所以這裏需要按照官網,進行解析,以下是PDF在線鏈接,本節使用Java8版本。
Java虛擬機規範1.8

打開《Java虛擬機規範》

image.png

解析

我們需要知道一個Class文件由哪些數據結構組成,並排列出來,一項數據佔幾個字節,這些我們都要知道。
我們首先需要記錄,這個Class文件的大體結構,Class文件的數據結構及順序都是需要嚴格按照《Java虛擬機規範》生成的,找到《Java虛擬機規範》中的 "The Class File Format (Class文件格式)"中的Class結構項。

image.png

需要解釋的是,這個ClassFile數據結構中的U2、u4分別代表兩個字節、四個字節,其對應的右邊的英文項,代表着其數據的常量項,Class文件是一定按照這個結構進行構件的,《Java虛擬機規範》中也説明了每一項的描述,本人結合官網整理如下:

image.png

這個是本人整理的Class文件的數據結構,有且只有這16項,具體的每一項,本文稍後都有解釋。其實Class文件並不複雜,只是Class中的引用比較多,例如constant_pool_info中,這是一個常量池,池中記錄着類、方法、字面量等描述符,是相互引用的方式。

javap查看class文件具體結構

使用javap查看文件結構,主要是為了供我們於Class二進制方式進行比對時的一個參照物,以説明我們解讀class文件時得出的結論是正確的。其餘我們需要確定我們常量池中的順序以及所對應的常量池名。

javap -v TestClass.class

輸出結果

image.png

根據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個字節。

image.png

隨後將CAFEBABE填入我們的yaml文件中:

image.png

小版本號

小版本號佔用2個字節,因此,將class文件中的0000轉換為十進制為0,所以小版本號為0;

大版本號

。。。

user avatar docker_app 頭像 yadong_zhang 頭像 mo_or 頭像 shadowck 頭像 yexiaobai_616e2b70869ae 頭像 jacheut 頭像 zoux 頭像
7 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.