代碼敲了很久,但是一直沒有怎麼去研究他的整個的過,最近有時間就研究了一下,總結後就寫了JVM系列的博客,以便總結與回顧。
java從編碼到執行的過程如下圖一所示:
java 文件通過 javac 編譯後成 class 文件,class 文件由 classLoader 加載進 JVM ,加載後由字節碼解釋器解釋後交給執行引擎,最後由執行引擎交給操作系統供其調用 。當某個文件執行的非常平凡的時候就會由JIT(即時編譯器)編譯,下次再執行的時候就不要解釋器再一句一句的解釋執行,效率會高很多。一般情況下都是混合模式,通過 java -version可以查看,如下圖二:
接下來就是就開始進入正題了,ClassFileFormat 到底是什麼呢?其實就是class文件的格式,接下來我就作詳細的介紹。我寫一個簡單的java類,如下圖三:
public class Demo1 {
int i = 0;
String s = "Hello ByteCode!";
public Demo1(int i, String s) {
this.i = i;
this.s = s;
}
public void m() {}
}
我們再通過插件 BinEd-Binary 插件打開Demo1.class 文件,如下圖四所示:
或許直接看16進制的看不明白,沒關係,我,二面還可以用 jclasslib 插件打開Demo1.class 文件,如下圖五所示:
這裏我們就看見了一個class文件的大概輪廓,還有javap -v + class文件全限定名 也可以達到相同的效果。在《深入理解java虛擬機》的第六章第二節裏面就可以看到對class文件格式的詮釋。如下:
- class文件“基本類型表一
u1 | 1個字節,無符號類型 |
u2 | 2個字節,無符號類型 |
u4 |
4個字節,無符號類型 |
u8 | 8個字節,無符號類型 |
- ClassFile 表的格式表二
類型 | 名稱 | 數量 |
---|---|---|
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 | thsi_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 |
attributes_info | attributes | attributes_count |
ClassFile 表中各項簡介如下:
- magic(魔數)
每個Java class 文件的前4個字節被稱爲他的魔數(magic number):0x CAFEBABE (圖四的前四個字節)。魔數的作用在於,可以輕鬆的分辨出java class文件和非java class 文件。如果一個文件不是以0xCAFEBABE 開頭的,那他肯定不是java class文件。 - minnor_version 和 major_version
class文件的下面4個字節包含了主、次版本號。隨着Java 技術的發展,java class 文件格式可能會加入新特性。class 文件格式一旦發生變化,版本號也會隨之變化。對於java 虛擬機來說,版本號確定了特定的class文件格式,通常只有給定主版本號和一系列次版本號後,java虛擬機才能夠讀取class文件。如果class文件的版本號超出了java虛擬機所能處理的有效範圍,java虛擬機不會處理該class文件。jdk 1.8 的版本號是 52. - constant_pool.count 和 constant_pool
class 文件中,魔數和版本號後面的是常量池。常量池包含了與文件中類和接口相關的常量。常量池中存儲了諸如文字字符串、final 變量值、類名和方法名的常量。常量池標誌如下表三 :入口類型 標誌值 描述 CONSTANT_Utf8 1 UTF-8 編碼的Unicode字符串 CONSTANT_Integer 3 int類型字面值 CONSTANT_Float 4 float 類型字面值 CONSTANT_Long 5 long類型字面值 CONSTANT_Double 6 double 類型字面值 CONSTANT_Class 7 對一個類或接口的符號引用 CONSTANT_String 8 string 類型字面值 CONSTANT_Fieldref 9 對一個字段的符號引用 CONSTANT_Methodref 10 對一個類中聲明的方法的符號引用 CONSTANT_InterfaceMethodref 11 對一個接口中聲明的方法的符號引用 CONSTANT_NameAndType 12 對一個字段或方法的部分符號引用 - access_flags
緊接常量池後面的兩個字節稱爲 access_flags ,他展示了文件中定義的類或接口的幾段信息。classFile表內access_flags的標誌位如下表四:標誌名 值 設置後的含義 設置名 ACC_PUBLIC 0x0001 public 類型 類和接口 ACC_FINAL 0x0010 類爲final類型 只有類 ACC_SUPER 0x0020 使用新型的invokespecial語義 類和接口 ACC_INTERFACE 0x0200 接口類型,不是類 類型 所有的接口,沒有類 ACC_ABSTRACT 0x0400 abstract類型 所有的接口,部分類 - this_class
接下來的兩個字節爲this_class項,它是一個隊常量池的索引。例如:圖五右邊的 this_class,淺綠色的 cp_info #5 就是指向常量池的第五個常量,然後繼續指向常量池的第26個常量,就得到了類的全限定名 - super_class
在class文件中,緊接在this_class 之後的是 super_class 項,它是一個兩個字節的常量池索引。與this_class類似,直接查看圖五右邊的 super_class 即可 - interfaces_count 和 intefaces
緊接着 super_class 的是 interfaces_count。此項的含義爲:在文件中該類直接實現或者由接口所擴展的父接口的數量。在這個計數的後面,是名爲 interfaces 的數組,它包含了對每個由該類或者接口直接實現的父接口的常量池索引。 - fields_count 和 fields
在class文件中,緊接在 interfaces 後面的是對在該類或者接口中所聲明的字段的描述。首先是名爲 fields_count 的計數,它是類變量和實例變量的字段的數量總和。在這個計數後面的是不同長度的 field_info 表的序列。只有在文件中由類或者接口聲明瞭的字段才能在 fields 列表中列出。在 fields 列表中,不列出從超類或者父接口繼承而來的字段。另一方面,fields 列表可能會包含在對應的java源文件中沒有敘述的字段,這是因爲java編譯器可能會在編譯時向類或者接口添加字段,添加進去的字段使用 Synthetic 屬性標識。fields_descriptor 標識對應如下表五所示:B byte
C char D double F float I int J long S short Z boolean V void L Object [ array(例如:[B ,表示 byte[] [Ljava/lang/String 表示 string[] ,多維數組 [[C [[[Ljava/lang/String) - methods_count 和 methods
在class文件中緊接着fields 後面的是對該類或者接口中所聲明的方法的描述。首先是名爲 methods_count 的計數,它是一個雙字節長度的對於該類或者接口中聲明的所有方法的總計數。這個總計數只包含在該類或者接口中顯式定義的方法(從超類或者父接口中集成來的方法不被計入)。在metnod_count 後面的是方法的本身,他在一個 methid_info 表的列表中進行了闡述(methids_count 指出了列表中有多少個method_info 表)。如下圖五所示:
還有就是方法裏面的邏輯運算等,如下圖六所示:
圈出的這部分內容其實就是java 的彙編語言,在 jvms 8 的第六、七章有說明,jvms 的下載地址爲 https://docs.oracle.com/javase/specs/index.html,值得注意的是一定要注意版本。 - <()V>代表的是方法 m 的參數類型和返回值類型,例子給出的是無參和無返回值,所以是這個樣子。
- attributes_count 和 attributes
class 文件中最後的部分是屬性(attribute),他給出了在改文件中類或者接口所定義的屬性的基本信息。屬性部分由 attributes_count 開始,attributes_count 是指出現在後續 attributes 列表中的 attributes_info 表的數量總和。每個 attributes_info 的第一項是指向常量池中 CONSTANT_Utf8_info表的索引,該表給出了屬性的名稱。
這次ClassFileFormat就介紹到這裏,如果有不正確地 地方還望大佬指正,謝謝!