Java虛擬機——類文件結構(一)

《深入理解Java虛擬機》第二版 周志明

第六章 類文件結構 p162

無關性基石

時至今日,商業機構和開源機構已經在Java語言之外發展出一大批在Java虛擬機之上運行的語言,如Clojure、Groovy、 JRuby、 Jython、 Scala 等。

實現語言無關性的基礎仍然是虛擬機和字節碼存儲格式。Java 虛擬機不和包括Java在內的任何語言綁定,它只與“Class文件”這種特定的二進制文件格式所關聯,Class 文件中包含了Java虛擬機指令集和符號表以及若干其他輔助信息。

任何其他語言的實現者都可以將Java虛擬機作爲語言的產品交付媒介。例如,使用Java編譯器可以把Java代碼編譯爲存儲字節碼的Class文件,使用JRuby等其他語言的編譯器一樣可以把程序代碼編譯成Class文件,虛擬機並不關心Class的來源是何種語言,如圖6-1所示。

Java語言中的各種變量、關鍵字和運算符號的語義最終都是由多條字節碼命令組合而成的,因此字節碼命令所能提供的語義描述能力肯定會比Java語言本身更加強大。因此,有一些Java語言本身無法有效支持的語言特性不代表字節碼本身無法有效支持,這也爲其他語言實現一些有別於Java的語言特性提供了基礎。
Java虛擬機提供的語言無關性

Class類文件的結構

Class文件格式

1. 魔數與Class文件的版本

0xCAFEBABE

2. 常量池

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

  • 類和接口的全限定名(Fally Qualifed Name )
  • 字段的名稱和描述符(Descriptor)
  • 方法的名稱和描述符
    (在JDK的bin目錄中,Oracle公司已經爲我們準備好一個專門用於分析Class文件字節碼的工具:javap;)

3. 訪問標誌

訪問標誌

4. 類索引、父類索引與接口索引集合

類索引(this_ class) 和父類索引(super clas)都是一個u2類型的數據,而接口索引集合(interfaces)是一組u2類型的數據的集合,Class文件中由這三項數據來確定這個類的繼承關係。類索引用於確定這個類的全限定名,父類索引用於確定這個類的父類的全限定名。接口索集合就用來描述這個類實現了哪些接口,這些被實現的接口將按implements語句後的接口順序從左到右排列在接口索引集合中。

5. 字段表集合 p175

字段表結構字段訪問標誌 描述符標識字符含義

6. 方法表集合 p178

方法的定義可以通過訪問標誌、名稱索引、描述符索引表達清楚,但方法裏面的代碼去哪裏了?方法裏的Java代碼,經過編譯器編譯成字節碼指令後,存放在方法屬性表集合中一個名爲“Code”的屬性裏面。
方法表結構
方法訪問標誌

7. 屬性表集合 p180

· code屬性 p182

Java程序方法體中的代碼經過Javac編譯器處理後,最終變爲字節碼指令存儲在Code屬性內。
Code屬性表的結構

· Exceptions屬性 p188

屬性表結構

· LineNumberTable屬性 p189

LineNumberTable屬性用於描述Java源碼行號與字節碼行號(字節碼的偏移量)之間的對應關係。它並不是運行時必需的屬性,如果選擇不生成LineNumberTable屬性,對程序運行產生的最主要的影響就是當拋出異常時,堆棧中將不會顯示出錯的行號,並且在調試程序的時候,也無法按照源碼行來設置斷點。
LineNumberTable 屬性結構
line_ number_table 是- -個數量爲linc_ number_tablc_ length、 類型爲line_ number_ info 的集合,line_ number_ jinfo 表包括了start_ pc和line_ number 兩個u2類型的數據項,前者是字節碼行號,後者是Java源碼行號。

· LocalVariableTable屬性 p189

LocalVariableTable屬性用於描述棧幀中局部變量表中的變量與Java源碼中定義的變量之間的關係,它也不是運行時必需的屬性,如果沒有生成這項屬性,最大的影響就是當其他人引用這個方法時,所有的參數名稱都將會丟失,IDE將會使用諸如arg0、arg1之類的佔位符代替原有的參數名,這對程序運行沒有影響,但是會對代碼編寫帶來較大不便,而且在調試期間無法根據參數名稱從上下文中獲得參數值。

· SourceFile屬性 p190

SourceFile屬性用於記錄生成這個Class文件的源碼文件名稱。這個屬性也是可選的,如果不生成這項屬性,當拋出異常時,堆棧中將不會顯示出錯代碼所屬的文件名。

· ConstantValue屬性 p191

ConstantValue屬性的作用是通知虛擬機自動爲靜態變量賦值。只有被static關鍵字修飾的變量(類變量)可以使用這項屬性。

· InnerClasses屬性 p192

InnerClasses屬性用於記錄內部類與宿主類之間的關聯。如果一個類中定義了內部類,那編譯器將會爲它以及它所包含的內部類生成InnerClasses屬性。

· Deprecated及Synthetic屬性 p193

Deprecated屬性用於表示某個類、字段或者方法,已經被程序作者定爲不再推薦使用,它可以通過在代碼中使用@deprecated註釋進行設置。
Synthetic屬性代表此字段或者方法並不是由Java源碼直接產生的,而是由編譯器自行添加的,其中最典型的例子就是Bridge Method。

· StackMapTable屬性 p193

StackMapTable屬性在JDK 1.6 發佈後增加到了Class 文件規範中,它是一-個複雜的變長屬性,位於Code屬性的屬性表中。這個屬性會在虛擬機類加載的字節碼驗證階段被新類型檢查驗證器(Type Checker)使用(見7.3.2節),目的在於代替以前比較消耗性能的基於數據流分析的類型推導驗證器。
StackMapTable屬性中包含零至多個棧映射幀(Stack Map Frames),每個棧映射幀都顯式或隱式地代表了一個字節碼偏移量,用於表示該執行到該字節碼時局部變量表和操作數棧的驗證類型。類型檢查驗證器會通過檢查自標方法的局部變量和操作數棧所需要的類型來確定一段字節碼指令是否符合邏輯約束。StackMapTable 屬性的結構見表6-27。
StackMapTable 屬性的結構

· Signature屬性 p194

Signature屬性在JDK 15發佈後增加到了Class文件規範之中,它是一個可選的定長屬性,可以出現於類、屬性表和方法表結構的屬性表中。在JIDK 1.s中大幅增強了Jjava語言的語法,在此之後,任何類:按口、初始化方法或成員的泛型簽名如果包含了類型變量(cTypeVariabies)"或參數化類型(Parametenized Types ),則Signature屬性會爲它記錄泛型簽名信息。

· BootstrapMethods屬性 p195

這個屬性用於保存invokedynamic指令引用的引導方法限定符。

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