要深刻學習Java以及Java虛擬機,深刻學習Java字節碼文件是繞不開的一條路,只有知道了字節碼文件裏的排列結構,你才能透徹的瞭解在JVM裏,類加載是怎麼加載Java類的,是怎麼將二進制流轉化爲運行時數據結構的。html
Class文件是是一組以8字節爲基礎單位的二進制流,各個數據項目嚴格按照順序緊湊地排列在Class文件中,中間沒有任何分隔符。java
這裏的Class文件其實不是特指Java的字節碼文件,任何編程語言的編譯器只要按照字節碼文件規範編譯成Class文件,均可以在JVM上運行,因此字節碼文件和JVM是和語言無關的。c++
另一般Class文件指的不必定是存儲在磁盤上的以.class後綴結束的文件,是一種泛指,指的是一切按照字節碼文件規範排列的二進制字節流。編程
Class文件採用下面這種相似C語言的結構體的僞結構來存儲數據,整個Class文件是一張表,表裏又由無符號數和表組成。數組
ClassFile {
u4 magic; // 魔數,固定爲"0xCAFEBABY"
u2 minor_version; //jdk次版本號
u2 major_version; //jdk主版本號
u2 constant_pool_count; //常量池數組大小,從1計數
cp_info constant_pool[constant_pool_count - 1]; //常量池數組
u2 access_flags; //類的訪問標誌,如:public
u2 this_class; //類索引,指向常量池中的類符號引用
u2 super_class; //父類索引,指向常量池中的類符號引用
u2 interfaces_count; //實現的接口的數量
u2 interfaces[interfaces_count]; //接口列表,按implements後面的接口順序
u2 fields_count; //字段數
field_info fields[fields_count]; //字段表
u2 methods_count; //方法數
method_info methods[methods_count]; //方法表
u2 attributes_count; //屬性表大小
attribute_info attributes[attributes_count]; //屬性表
}
複製代碼
從上面的僞結構能夠看到,Class文件根據上面的順序把規定的數據類型按照佔用的字節依次排列下來。bash
下面經過一個例子來實戰分析一下Class文件數據結構
//Test.class
public class Test {
public static int a = 1;
public static final int b = 1;
public void say(){
System.out.println("Hello");
}
}
複製代碼
(2) u2 minor_version
2個字節(000h:45)次版本號: 0x0000, 次版本號爲0編程語言
(3) u2 major_version
2個字節(000h:67)主版本號: 0x0034,即52,JDK1.0-1.1:45.0 ~ 45.3, 1.1後版本增1,數字加1,因此這裏用的是1.1 + 0.(52-45) = 1.8工具
(4) u2 constant_pool_count
2個字節(000h:89)常量池大小:0x0027,即39,常量池數組是從1開始計數的,說明常量池中有38個常量,後面依次排列的就是常量池的38個常量post
(5) cp_info constant_pool[constant_pool_count - 1]
常量池所佔的字節數是由常量池中常量的數量以及類型所決定的,這裏有38個常量,每一個常量開頭都有一個字節的tag標識常量的類型,具體類型能夠參考最下面的腦圖,根據這個標識能夠找到這個常量所佔的字節以及含義,下面分析其中一個常量,其他的讀者有興趣能夠所有完成
<init>
,描述符是()V
這樣第一個常量就分析完成,共佔5個字節,表示的是方法符號引用,該方法所在的類是Object類,方法名稱是<init>
, 無參數,返回值是void
藉助工具javap能夠更直觀的看到咱們剛剛分析的部分結果以及所有類文件的結構,使用如下命令便可:
javap -v Test.class
複製代碼
結果如圖:
經過上面的圖能夠看到,和咱們上面的部分分析是一致的
下面是我在看《深刻理解Java虛擬機》這本書的時候整理的關於Class文件結構的腦圖,圖片比較大,右鍵另存爲圖片再查看會更方便。
原文連接:www.jackielee.cn/posts/7eb7d…
更多幹貨請掃碼關注