Java虛擬機學習之類文件結構

一、語言無關性與平臺無關性

語言無關性:Java虛擬機上運行的是Class文件(字節碼文件*.class),而Class文件不一定由Java程序編譯而來,JRuby經過jrubyc編譯器編譯生成的是Class文件,Groovy程序經過groovyc編譯器編譯後生成的也是class文件,都可在虛擬機上運行,虛擬機不關心Class的來源是何種語言。

平臺無關性:一次編寫,到處運行,各種不同平臺的虛擬機與所有平臺都統一使用的程序存儲格式——字節碼。


二、Class類文件的結構

以字節爲基礎單位:
Class文件是一組以8位字節爲基礎單位的二進制流,各數據項目嚴格按照順序緊湊地排列在Class文件之中,中間沒有添加任何分隔符。當遇到需要佔用8位字節以上空間的數據項時,則會按照高位在前的方式分割成若干個8位字節進行存儲。

兩種數據類型:無符號數和表
無符號數屬於基本的數據類型,u1表示1個字節,u2表示2個字節,u4代表4個字節。
表是由多個無符號數或者其他表作爲數據項構成的符合數據類型。

魔數:
Class文件的頭4個字節稱爲魔數,確定這個文件是否爲一個能被虛擬機接收的Class文件。值爲0xCAFEBABE。

版本號:
緊接着4個字節存儲的是Class文件的版本號。Minor Version(2字節)+Major Version(2字節)。

常量池:
緊接着版本號的是常量池入口,常量池可以理解爲Class文件之中的資源倉庫。
主要存放兩大類常量:字面量和符號引用。
字面量:文本字符串、聲明爲final的常量值等。
符號引用:類和接口的全限定名、字段的名稱和描述符、方法的名稱和描述。
Java代碼在進行編譯時,不像C和C++那樣有“連接”這一步驟,而是虛擬機加載Class文件的時候進行動態連接。

訪問標誌:
用於識別一些類或者接口層次的訪問信息,包括Class是類還是接口,是否爲public類型,是否abstract類型,是否爲final類型。

類索引、父類索引接口與接口索引集合:
類索引:u2類型的數據,指向一個類型爲CONSTANT_Class_info的類描述符常量,通過CONSTANT_Class_info類型中的索引值可以找到定義在CONSTANT_Utf8_info類型的常量中的全限定名字符串。
父類索引:u2類型,其他和上面一樣。
接口索引集合:因爲單個類可以實現多個接口,所以入口的第一項爲u2類型的接口計數器。後面是接口集合。

字段表集合:
用於描述接口或者類中聲明的變量。
字段的修飾符(有或無,布爾類型)用標誌位來表示。如public、static、final等
字段的名字、字段被定義爲什麼數據類型,這些無法固定,只能引用常量池的常量來表示。
字段表集合中不會列出從超類或者父接口中繼承而來的字段,但有可能列出原本Java代碼之中不存在的字段,譬如內部類爲了保持對外部類的訪問性,會自動添加指向外部類實例的字段。

方法表集合:
類似於字段表集合,包括訪問標誌、名稱索引、描述符索引、屬性表集合。
描述方法的定義,方法裏面的代碼存放在方法屬性表集合中一個名爲Code的屬性裏面。
其中<init>爲編譯器爲添加的的實例構造器。
如果父類方法在子類中沒有被重寫,方法表集合中就不會出現來自父類的方法信息。
要重載一個方法,除了要與原方法有相同的簡單名稱之外,要求有一個與原方法不同的特徵簽名。特徵簽名就是一個方法中各個參數在常量池中字段符號引用的集合,返回值不會包含在特徵簽名中,因此無法靠返回值的不同來對一個已有方法進行重載。

屬性表集合:
Class文件、字段表、方法表都可以攜帶自己的屬性表集合。



三、字節碼指令

1、字節碼指令長度

操作碼爲1個字節,不對齊,有利於提高傳輸效率。

2、字節碼與數據類型

iload指令用於從局部變量表中加載int型的數據到操作數棧。(fload則float)

虛擬機內部對不同數據類型的指令可能是同一種實現方式。

大部分指令都沒有支持整數類型byte,char和short,編譯器在編譯器或運行期將這些類型數據零位擴展爲響應的int類型數據。


3、加載和存儲指令

iload_<n>:將一個局部變量加載到操作棧。

istore_<n>:將一個數值從操作數棧存儲到局部變量表。

iconst<i>:將一個常量加載到操作數棧。

4、運算指令

5、類型轉換指令

6、對象創建與訪問指令

7、操作數棧管理指令

8、控制轉移指令

9、方法調用和返回指令

10、異常處理指令

11、同步指令

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章