1. 程式人生 > >JAVA類檔案Class內部結構

JAVA類檔案Class內部結構

文章目錄

JAVA的平臺無關性怎麼實現的?

位元組碼是構成平臺無關係的基石。JAVA在剛剛誕生時就提出"Write Once, Run Anywhere",將編寫的程式編譯成所有平臺都可以使用的程式儲存格式:位元組碼。JAVA虛擬機器不和任何語言繫結,它只與"Class檔案"這種二進位制檔案格式相關聯。任意一門功能性語言都可以把程式程式碼編譯成Class檔案被JAVA虛擬機器接受,如Scala、Clojure、Groovy、JRuby、Jython等。

JAVA的類檔案結構?

Class檔案格式採用一種偽結構來儲存資料,包括兩種資料型別:無符號數和表。整個Class檔案本質上就是一張表:

型別 名稱 數量
u4 magic 1
u2 minor_version 1
u2 major_version 1
u2 constant_pool_count 1
cp_info constant_pool constant_pool_count-1
u2 access_flags 1
u2 this_class 1
u2 super_class 1
u2 interfaces_count 1
u2 interfaces interfaces_count
u2 fields_count 1
field_info fields fields_count
u2 methods_count 1
method_info methods methods_count
u2 attributes_count 1
attribute_info attributes attributes_count

從上到下分析:

魔數與版本

開頭4個位元組(u4)稱為魔數(Magic Number),它唯一作用是表明這是一個能被虛擬機器接受的Class檔案。這四個位元組用16進位制來表示是0xCAFEBABE。
緊接著的u2兩個位元組是次版本號,再後面u2兩個位元組是主版本號。

常量池

由於常量池中常量的數量是不固定的,所以先用u2標明容量(constant_pool_count) 。如果是0x0016,則表明有21個常量(1*16+6-1)。 只有常量池的容量是從1開始計數的,其他集合型別都是從0開始計數。
常量池存放兩大類常量:字面量和符號引用。字面量如文字字串、宣告為final的常量值等。符號引用包括:類和介面的全限定名、欄位的名稱和描述符、方法的名稱和描述符。符號引用不經過執行期轉換無法轉為真正的記憶體地址。每個常量都有一個tag位(u1)來標明常量的型別,如整型字面量、浮點型字面量、類和介面的符號引用、欄位或方法的符號引用等。可用javap命令來輸出Class檔案的位元組碼。

javap -verbose TestClass

訪問標誌

access_flags為兩個位元組,標明是否為類或介面,是否為public、abstract、final等。

類索引父類索引與介面索引集合

this_class(類索引)、super_class(父類索引)各自指向一個型別為CONSTANT_Class_info的類描述符常量,通過其索引值name_index可以找到常量池中的全限定名。

欄位表集合

欄位表(field_info)包括類和介面中宣告的變數。
變數會由各種修飾符來定義:public/private/protected、static、final、volatile、transient、int/long/float、是陣列還是物件等等。
每個欄位由access_flags、name_index、descriptor_index來表示,即欄位修飾符、簡單名稱索引和描述符索引。簡單名稱可理解為變數名,實際值存在常量池中,這裡只維護引用。描述符用大寫字母表示:I代表int,B代表byte,J代表long,Z代表boolean、L代表物件型別等等。

方法表集合

方法表跟欄位表相似,多了一個屬性表集合。

屬性表集合

在Class檔案、欄位表、方法表中都可以攜帶屬性表。
如方法表中的Code、欄位表中的ConstantValue、Code屬性中的LineNumberTable、LocalVariableTable、StackMapTable。
屬性的名稱在常量池中,由attribute_name_index引用。
這裡只介紹Code屬性:除了介面或抽象類中的方法,其他的方法體編譯後的位元組碼指令儲存在Code屬性內。包括屬性名索引、屬性長度、運算元棧最大深度、區域性變量表所需空間、原始碼生成的位元組碼指令、異常表等。

Class檔案的基礎單位是什麼?

8位位元組的二進位制流。如果超出8位,高位在前(Big-Endian)。

方法裡的JAVA程式碼編譯成位元組碼後存放在哪裡?

Code屬性裡面。

子類方法表會不會有父類的方法?

不會,除非子類重寫(Override)了父類方法。

參考資料

《深入理解Java虛擬機器:JVM高階特性與最佳實踐(第2版)》 周志明 著
http://icyfenix.iteye.com