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