一、什么是Java類文件 Java類文件是Java程序的二進(jìn)制表示形式。每一個(gè)類文件代表一個(gè)類或者接口。不可能在一個(gè)類文件中放入多個(gè)類或者接口。這樣就使得無(wú)論類文件是在哪一種平臺(tái)上生成,都可以在任何主機(jī)上執(zhí)行。 雖然類文件是Java體系結(jié)構(gòu)的一部分,但是他并不是與Java語(yǔ)言不可分的。你可以將其他語(yǔ)言的程序編譯為類文件,也可以將Java程序文件編譯為其他二進(jìn)制形式。 Java類文件是一個(gè)基于8-bit字節(jié)的二進(jìn)制流。數(shù)據(jù)塊順序的、無(wú)分割符的、big-endian的形式存儲(chǔ)。 二、類文件的內(nèi)容 Java的類文件中包含了所有Java虛擬機(jī)所需要的關(guān)于類和接口的信息。所有類文件中的信息都以以下的四種基本類型的存儲(chǔ): Table 6-1. Class file "primitive types" u1 a single unsigned byte u2 two unsigned bytes u4 four unsigned bytes u8 eight unsigned bytes 類文件中的主要部分以表6-2的順序存儲(chǔ): Table 6-2. Format of a ClassFile Table Type& #9;Name Count 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 1、魔術(shù)編碼(magic) 每一個(gè)Java類文件的開(kāi)頭四個(gè)字節(jié)都是魔術(shù)編碼(OxCAFEBABE)。通過(guò)魔術(shù)編碼可以很容易識(shí)別類文件。 2、副版本號(hào)和主版本號(hào)(minor_version and major_version) 剩下的四個(gè)字節(jié)是副版本號(hào)和主版本號(hào)。但Java技術(shù)在進(jìn)化時(shí),一些新的特性可能會(huì)被加入到類文件中。每一次類文件格式的變化,都會(huì)相應(yīng)的改變版本號(hào)。虛 擬機(jī)通過(guò)版本號(hào)來(lái)識(shí)別自己能夠處理的類文件。Java虛擬機(jī)往往只能處理一個(gè)給定的主版本號(hào)和其下的一些副版本號(hào)。虛擬機(jī)必須拒絕那些不再處理范圍內(nèi)的類 文件。 3、常量個(gè)數(shù)和常量池(constant_pool_count and constant_pool) 接下來(lái)的就是常量池,常量池中包含了哪些被類或者接口訪問(wèn)過(guò)的常量,比如:字符串,常量(final variable values),類名,方法名。常量池作為一個(gè)列表存儲(chǔ)。列表中常量的個(gè)數(shù)就是之前保存的“constant_pool_count”。 很多常量池中的常量都引用了常量池中的其他常量,那些引用常量池常量的引用最終也會(huì)轉(zhuǎn)換為對(duì)常量池中常量的直接引用。雖然常量列表中的索引是從1開(kāi)始的,但是常量個(gè)數(shù)還是包含了0,比如一個(gè)常量列表中有15個(gè)常量,那么它的常量個(gè)數(shù)就為16。 每一個(gè)常量開(kāi)頭都會(huì)有一個(gè)標(biāo)志,以表示他的類型。當(dāng)虛擬機(jī)讀取這個(gè)標(biāo)志時(shí),就會(huì)知道這個(gè)常量的具體類型了。表6-3列舉了這些標(biāo)志: Table 6-3. Constant pool tags Entry Type Tag Value Description CONSTANT_Utf8 1 A UTF-8 encoded Unicode string CONSTANT_Integer 3 An int literal value CONSTANT_Float 4 A float literal value CONSTANT_Long 5 A long literal value CONSTANT_Double 6 A double literal value CONSTANT_Class 7 A symbolic reference to a class or interface CONSTANT_String 8 A String literal value CONSTANT_Fieldref 9 A symbolic reference to a field CONSTANT_Methodref 10 A symbolic reference to a method declared in a class CONSTANT_InterfaceMethodref 11 A symbolic reference to a method declared in an interface CONSTANT_NameAndType 12 Part of a symbolic reference to a field or method 表6-3中的每一個(gè)標(biāo)志都會(huì)有一個(gè)相應(yīng)的表格,用來(lái)描述這個(gè)標(biāo)志的所表示的一些詳細(xì)信息,這些對(duì)應(yīng)的標(biāo)志都會(huì)以標(biāo)志名+_INFO來(lái)結(jié)尾。比如CONSTANT_CLASS標(biāo)志對(duì)應(yīng)的就是CONSTANT_CLASS_INFO。 常量池在程序的動(dòng)態(tài)鏈接中扮演了很重要的角色。除了上邊所說(shuō)的各種常量值以外,常量池中包含了一下三種符號(hào)引用:類和接口的全名,字段名和描述符,方法名 和描述符。一個(gè)字段是一個(gè)類或者接口中的實(shí)例或者類變量,字段描述符是字段的類型。方法的描述符是方法和返回值和參數(shù)的個(gè)數(shù)、順序和類型。在虛擬機(jī)將這個(gè) 類或者接口鏈接到其他類或者接口時(shí)用到這些全名。因?yàn)轭愇募话魏侮P(guān)于內(nèi)存結(jié)構(gòu)的信息,所以這個(gè)鏈接只能以符號(hào)引用的形式存在。虛擬機(jī)在執(zhí)行時(shí)將這些 符號(hào)引用轉(zhuǎn)換為實(shí)際的地址。具體的信息參見(jiàn)第八章“The Linking Model”。 4、訪問(wèn)標(biāo)志(access_flags) 緊接在常量池后面的兩個(gè)字節(jié)就是訪問(wèn)標(biāo)志,表示這個(gè)類或者接口的幾方面信息,他有如下幾種值: Table 6-4. Flag bits in the access_flags item of ClassFile tables Flag Name Value Meaning if Set Set By ACC_PUBLIC 0x0001 Type is public Classes and interfaces ACC_FINAL 0x0010 Class is final Classes only ACC_SUPER 0x0020 Use new invokespecial semanticsClasses and interfaces ACC_INTERFACE 0x0200 Type is an interface, not a class All interfaces, no classes ACC_ABSTRACT 0x0400 Type is abstract All interfaces, some classes ACC_SUPER標(biāo)志是為了兼容以前SUN的老式的編譯器。所有沒(méi)有使用的訪問(wèn)標(biāo)志,必須設(shè)置為0。 5、類名(this_class) 接下來(lái)的兩個(gè)字節(jié)保存了一個(gè)常量池的索引。這個(gè)常量池中的實(shí)體必須是CONSTANT_CLSS_INTO類型的,他包含了標(biāo)志和名字索引。標(biāo)志就是 CONSTATN_CLASS,那個(gè)名字索引應(yīng)該是一個(gè)保存了這個(gè)類或者接口全名的CONSTANT_UTF8_INFO類型的索引。 6、父類(super_class) this_class之后的就是兩個(gè)字節(jié)的super_class,他也是一個(gè)常量池的索引,其中保存了父類的全名,處理this_class一樣。當(dāng)父 類是java.lang.Object時(shí),super_class都應(yīng)該是0。對(duì)于接口super_class都是0。 7、(interfaces_count and interfaces) interfaces_count中保存了父接口的個(gè)數(shù),interfaces中以數(shù)組形式保存了一些常量池的索引。每一個(gè)索引都指向了一個(gè) CONSTANT_CLASS_INFO的常量,其中保存了每一個(gè)父接口的全名。這個(gè)數(shù)組的順序就是父接口出現(xiàn)在在implements、extends 語(yǔ)句中從左到右的順序。 8、(fields_count and fields) 字段被保存在一個(gè)field_info的列表中,fields_count是這個(gè)列表的長(zhǎng)度。Field_info列表中保存的只是類或者接口中的申明的變量,從父類或者父接口中繼承的字段不保存在這里。 每一個(gè)field_info表中的一條都描述了一個(gè)字段的信息,包括:字段名,描述符,訪問(wèn)權(quán)限。如果一個(gè)字段被申明為final,那么這個(gè)字段的信息即會(huì)保存在field_info表中,也會(huì)保存在常量池中。 9、(methods_count and methods) 方法的信息都保存在method_info表中,mehtods_count是表的長(zhǎng)度。Method_info表中只保存類或者接口中申明的方法,不保存從父類或者接口中繼承的方法。 Method_info 表中保存了方法名和描述符(返回值和參數(shù)類型)。如果不是抽象方法,還會(huì)保存用于堆棧的大?。ū4姹镜刈兞坑玫模⒉僮鲾?shù)堆棧的最大值、捕捉的異常列表、 方法的字節(jié)碼、可選的行號(hào)和本地變量表。如果方法拋出一些被檢查的異常,method_info還會(huì)包含一個(gè)被檢查異常的列表。 10、(attributes_count and attributes) 類文件中最后的就是屬性個(gè)數(shù)和atribute_info列表。Atribute_info表中保存了一些指向常量池中constant_utf8_info的索引,其中保存了屬性的名字。Java虛擬機(jī)規(guī)范中定義了兩種類型的屬性:源代碼和內(nèi)部類。 三、特定字符串(Special Strings) 常量池中的字符引用包含三種特定字符串:全限定名,簡(jiǎn)單名,描述符。一個(gè)類或者接口的所有字符引用都必須包含一個(gè)全限定名。每一個(gè)字段或者方法都有一個(gè)簡(jiǎn) 單名和描述符作為全限定名的補(bǔ)充。這些特定字符串用來(lái)表示文件中定義的類和接口,包換類名,父類名,父接口名,每個(gè)字段和方法的簡(jiǎn)單名和描述符。 1、全名(Fully Qualified Names) 當(dāng)常量池中引用了類和接口時(shí),就會(huì)提供這個(gè)類或者接口的權(quán)限定名,比如java.lang.Object。 2、簡(jiǎn)單名(Simple Names) 字段和方法都以簡(jiǎn)單名的形式保存在常量池中。比如常量池中有一個(gè)java.lang.Object類的String toString()方法的引用,就會(huì)保存“toString”;java.lang.System類的java.io.PrintStream out字段,被保存為“out”。 3、描述符(Descripters) 字段和方法的字符引用都會(huì)包含一個(gè)描述符。字段的描述符提供了字段的類型。方法的描述符提供了方法的返回值、參數(shù)個(gè)數(shù)、參數(shù)類型。所有描述符得類型列表: FieldDescriptor: FieldType ComponentType: FieldType FieldType: BaseType ObjectType ArrayType BaseType: Terminal Type B byte C char D double F float I int J long S short Z boolean ObjectType: L<classname>; ArrayType: [ ComponentType ParameterDescriptor: FieldType MethodDescriptor: ( ParameterDescriptor* ) ReturnDescriptor ReturnDescriptor: FieldType V Table 6-6. Examples of field descriptors Descriptor Field Declaration I int i; [[J long[][] windingRoad; [Ljava/lang/Object; java.lang.Object[] stuff; Ljava/util/Hashtable; java.util.Hashtable ht; [[[Z boolean[][][] isReady; Table 6-7. Examples of method descriptors Descriptor Method Declaration ()I int getSize(); ()Ljava/lang/String; String toString(); ([Ljava/lang/String;)V void main(String[] args); ()V void wait() (JI)V void wait(long timeout, int nanos) (ZILjava/lang/String;II)Z boolean regionMatches(boolean ignoreCase, int toOffset, String other, int ooffset, int len); ([BII)I int read(byte[] b, int off, int len); 四、常量池 常量池被組織成為一個(gè)cp_info類型的列表,表6-8顯示了cp_info表的結(jié)構(gòu) Table 6-8. General form of a cp_info table Type Name Count u1 tag 1 u1 info depends on tag value 1、The CONSTANT_Utf8_info Table 2、The CONSTANT_Integer_info Table 3、The CONSTANT_Float_info Table 4、The CONSTANT_Long_info Table 5、The CONSTANt_Double_info Table 6、The CONSTANT_Class_info Table 7、The CONSTANT_String_info Table 8、The CONSTANT_Fieldref_info Table 9、The CONSTANT_Methodref_info Table 10、The COMSTANT_InterfaceMethodref_info Table 11、The CONSTANT_NameAndType_info Table 五、Fields 六、Methods 七、Attributes
|