本文介紹Java虛擬機的類文件格式。每個類文件都包含一個類或接口的定義没佑。雖然類或接口不需要有字面上包含在文件中的外部表示(例如,因為類是由類裝入器生成的),但我們口頭上將類或接口的任何有效表示稱為類文件格式笛洛。
java文件從編碼到執(zhí)行
1、首先我們有個x.java文件乃坤,通過javac命令編譯成x.class文件
2苛让、執(zhí)行java命令將x.class由ClassLoader加載到內(nèi)存里
3、通常我們在寫代碼的時候用到的java類庫也會被加載到內(nèi)存中
4湿诊、調(diào)用字節(jié)碼解釋器或JIT即時編譯器進行解釋或編譯
5狱杰、編譯完之后由執(zhí)行引擎通過os的硬件執(zhí)行
通常java都是使用解釋和編譯混合模式,非常常用的代碼就會由JIT(即時編譯器)編譯厅须,下次再執(zhí)行的時候就不要解釋器再一句一句的解釋執(zhí)行仿畸,效率會高很多,執(zhí)行引擎可以直接交給操作系統(tǒng)調(diào)用朗和,但是不是所有的代碼都由JIT編譯错沽,這樣就不能跨平臺了,所以java使用混合模式例隆。
JVM和語言無關
JVM和java并不是強綁定的甥捺,JVM只跟class格式的文件有關系,只要可以編譯出符合class規(guī)范的文件镀层,都可以在JVM上運行镰禾,所以JVM是定義了一種規(guī)范皿曲。目前可以運行在JVM上的語言有很多,比如Scala吴侦、groovy等等屋休。
類文件結構
類文件由單一的類文件結構組成:
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
類文件結構中的項如下:
magic(魔數(shù))
每個Java class 文件的前4個字節(jié)被稱為他的魔數(shù)(magic number):0x CAFEBABE 。魔數(shù)的作用在于备韧,可以輕松的分辨出java class文件和非java class 文件劫樟。如果一個文件不是以0xCAFEBABE 開頭的,那他肯定不是java class文件织堂。minor_version 和 major_version
minor_version和major_version項的值是這個類文件的主版本號和次版本號叠艳。主版本號和次版本號一起決定類文件格式的版本。如果一個類文件的主版本號為M易阳,次版本號為M附较,則我們將其類文件格式的版本表示為M. M。因此潦俺,類文件格式的版本可以按字典順序排列拒课,例如,1.5 < 2.0 < 2.1事示。比如java8就是52.0其中major_version就是52早像,minor_version就是0。-
constant_pool.count 和 constant_pool
class 文件中肖爵,魔數(shù)和版本號后面的是常量池卢鹦。constant_pool是一個結構表,它代表了各種字符串常量遏匆,類和接口名法挨,字段名谁榜,以及在類文件結構及其子結構中引用的其他常量幅聘。每個constant_pool表項的格式都由它的第一個“tag”字節(jié)表示。constant_pool表的索引從1到constant_pool_count - 1窃植。 常量池中的類型如下:入口類型 標志值 描述 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 對一個字段或方法的部分符號引用 CONSTANT_MethodHandle 15 方法句柄 CONSTANT_MethodType 16 方法類型 CONSTANT_InvokeDynamic 18 動態(tài)調(diào)用 -
access_flags
緊接常量池后面的兩個字節(jié)稱為 access_flags 帝蒿,access_flags項的值是一個標記的掩碼,用于表示該類或接口的訪問權限和屬性巷怜。下表規(guī)定了每個標志設置后的解釋葛超。標志名 值 設置后的含義 設置名 ACC_PUBLIC 0x0001 public 類型 類和接口 ACC_FINAL 0x0010 類為final類型 只有類 ACC_SUPER 0x0020 使用新型的invokespecial語義 類和接口 ACC_INTERFACE 0x0200 接口類型,不是類 類型 所有的接口延塑,沒有類 ACC_ABSTRACT 0x0400 abstract類型 所有的接口绣张,部分類 this_class
接下來的兩個字節(jié)為this_class項,它是一個隊常量池的索引关带。this_class項的值必須是constant_pool表的有效索引侥涵。索引處的constant_pool條目必須是CONSTANT_Class_info結構,它表示這個類文件定義的類或接口。super_class
在class文件中芜飘,緊接在this_class 之后的是 super_class 項务豺,它是一個兩個字節(jié)的常量池索引。對于一個類嗦明,super_class項的值必須為零或者必須是constant_pool表的有效索引笼沥。
如果super_class項的值為非零,則該索引處的constant_pool項必須是CONSTANT_Class_info結構娶牌,它表示這個類文件定義的類的直接超類奔浅。無論是直接超類還是它的任何超類都不能在它的類文件結構的access_flags項中設置ACC_FINAL標志。
如果super_class項的值為0诗良,那么這個類文件必須表示class對象乘凸,這是唯一沒有直接超類的類或接口。
對于接口累榜,super_class項的值必須始終是constant_pool表的有效索引营勤。索引處的constant_pool條目必須是表示類對象的CONSTANT_Class_info結構。interfaces_count 和 intefaces
緊接著 super_class 的是 interfaces_count壹罚。此項的含義為:在文件中該類直接實現(xiàn)或者由接口所擴展的父接口的數(shù)量葛作。在這個計數(shù)的后面,是名為 interfaces 的數(shù)組猖凛,它包含了對每個由該類或者接口直接實現(xiàn)的父接口的常量池索引赂蠢。-
fields_count 和 fields
在class文件中,緊接在 interfaces 后面的是對在該類或者接口中所聲明的字段的描述辨泳。首先是名為 fields_count 的計數(shù)虱岂,它是類變量和實例變量的字段的數(shù)量總和。在這個計數(shù)后面的是不同長度的 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[] ,多維數(shù)組 [[C [[[Ljava/lang/String) methods_count 和 methods
在class文件中緊接著fields 后面的是對該類或者接口中所聲明的方法的描述摹闽。首先是名為 methods_count 的計數(shù)蹄咖,它是一個雙字節(jié)長度的對于該類或者接口中聲明的所有方法的總計數(shù)。這個總計數(shù)只包含在該類或者接口中顯式定義的方法(從超類或者父接口中集成來的方法不被計入)付鹿。
方法表中的每個值都必須是method_info結構澜汤,該結構給出了這個類或接口中方法的完整描述铝量。如果在method_info結構的access_flags項中都沒有設置ACC_NATIVE和ACC_ABSTRACT標志,那么還會提供實現(xiàn)該方法的Java虛擬機指令银亲。
method_info結構表示由這個類或接口類型聲明的所有方法慢叨,包括實例方法、類方法务蝠、實例初始化方法和任何類或接口初始化方法拍谐。方法表不包括表示從超類或超接口繼承的方法的項。
如下所示:
圖中字節(jié)碼部分其實就是java 的匯編語言馏段,在 jvms 8 的第六轩拨、七章有說明,jvms 的下載地址為 https://docs.oracle.com/javase/specs/index.html院喜,值得注意的是一定要注意版本亡蓉。
- attributes_count 和 attributes
class 文件中最后的部分是屬性(attribute),他給出了在改文件中類或者接口所定義的屬性的基本信息喷舀。屬性部分由 attributes_count 開始砍濒,attributes_count 是指出現(xiàn)在后續(xù) attributes 列表中的 attributes_info 表的數(shù)量總和。屬性表的每個值都必須是一個attribute_info結構硫麻,每個 attributes_info 的第一項是指向常量池中 CONSTANT_Utf8_info表的索引爸邢,該表給出了屬性的名稱。