版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、JVM 之 Class文件結(jié)構(gòu)本文寫作目的:1)為了加深自己學(xué)習(xí)的理解,2)幫助正在學(xué)習(xí)研究JVM的同仁,3)與任何熱愛技術(shù)的達(dá)人交流經(jīng)驗(yàn),提升自己以此為本,文章會(huì)盡量寫的簡潔,盡量保證理解的正確性,如有任何理解不到位或錯(cuò)誤的地方,希望朋友們及時(shí)指出,嚴(yán)厲拍磚。開始之前我們需要先了解一些基本的概念,這些概念是學(xué)習(xí)整個(gè)JVM原理的基礎(chǔ)。1)JVM虛擬機(jī)規(guī)范主要規(guī)范了Class文件結(jié)構(gòu),虛擬機(jī)內(nèi)存結(jié)構(gòu),虛擬機(jī)加載,解析,執(zhí)行Class文件的行為方式,以及一系列的字節(jié)碼指令集。2)Class文件理論上說是一種數(shù)據(jù)結(jié)構(gòu),該數(shù)據(jù)結(jié)構(gòu)有著嚴(yán)格的格式規(guī)范,該規(guī)范在字節(jié)粒度上規(guī)定了組成該數(shù)據(jù)結(jié)構(gòu)的格式標(biāo)準(zhǔn)。)
2、Class文件本質(zhì)上是一組二進(jìn)制字節(jié)流,是被JVM解析執(zhí)行的數(shù)據(jù)源,每個(gè)字節(jié)都有著不同的含義,可能表示字符,數(shù)字,也可能表示執(zhí)行某種操作的一個(gè)字節(jié)碼指令。)JVM (Java 虛擬機(jī))是解析執(zhí)行Class文件的核心引擎,是整個(gè)Java系統(tǒng)的運(yùn)行時(shí)環(huán)境,是跨平臺的基石。)我們的Java代碼需要被編譯器編譯成完整,正確的Class文件才能被JVM正確的執(zhí)行。)編譯器并非JVM的一部分,不同的語言可以提供不同的編譯器,其作用是將該語言的代碼編譯為正確的Class文件,如Scala,JRuby等等。)JVM是完全開放的跨平臺的,只要你有能力你可以按照J(rèn)VM虛擬機(jī)規(guī)范編寫自己的編程語言。)JVM 使得J
3、ava的跨平臺成為可能,那么Class文件結(jié)構(gòu)規(guī)范則使得更多的編程語言運(yùn)行在JVM上成為可能。既然Class文件是一種數(shù)據(jù)結(jié)構(gòu),那么到底是什么樣的數(shù)據(jù)結(jié)構(gòu)呢?通常計(jì)算機(jī)中的文件都包含元數(shù)據(jù)和實(shí)體數(shù)據(jù)兩部分,元數(shù)據(jù)用來存儲該文件的描述信息,實(shí)體數(shù)據(jù)來存放用于表達(dá)文件真實(shí)內(nèi)容的數(shù)據(jù)。當(dāng)然Class文件也不例外,我們?yōu)榱吮阌诶斫?,也將class文件的結(jié)構(gòu)分為兩大部分:元數(shù)據(jù)和實(shí)體數(shù)據(jù)(注:非規(guī)范定義,只是為了方便理解進(jìn)行的自定義)。元數(shù)據(jù):包含了Class文件的魔術(shù)數(shù)(標(biāo)識符)和版本信息。實(shí)體數(shù)據(jù):包含了常量池,字段描述,方法描述,屬性描述等用于表述該類行為的具體信息。元數(shù)據(jù)我們不多贅述對我們后面的
4、分析沒多大關(guān)系,下面主要分析下實(shí)體數(shù)據(jù)。一,結(jié)構(gòu)概覽不管是元數(shù)據(jù)還是實(shí)體數(shù)據(jù)他們都以字節(jié)為單位按順序緊湊的排列在class文件中,沒有任何多余空間。為了描述class文件結(jié)構(gòu),虛擬機(jī)規(guī)范定義了u1, u2, u4, u8四種基本數(shù)據(jù)結(jié)構(gòu)和一種由這四種基本數(shù)據(jù)結(jié)構(gòu)組成的復(fù)雜數(shù)據(jù)結(jié)構(gòu)-表(通常以info結(jié)尾表示),這四種基本數(shù)據(jù)結(jié)構(gòu)分別表示一個(gè)字節(jié),兩個(gè)字節(jié),四個(gè)字節(jié),八個(gè)字節(jié)。基于此我們便可以清晰的了解class文件結(jié)構(gòu)的總體輪廓了(C語言語法,其中常量表,變量表,方法表,屬性表都有一到多個(gè),因此定義為數(shù)組),如?123456789101112131415161718class-fileu4ma
5、gic;/魔術(shù)數(shù)u2minor_version;/小版本號u2major_version;/大版本號u2constant_pool_count;/常量池中常量個(gè)數(shù)+1cp_infoconstant_poolconstant_pool_count-1;/常量池u2access_flags;/類的訪問控制符標(biāo)識(public,static,final,abstract等)u2this_class;/該類的描述(值為對常量池的引用,引用的值為CONSTANT_Class_info)u2super_class;/父類的描述(值為對常量池的引用,引用的值為CONSTANT_Class_info)u2in
6、terfaces_count;/接口數(shù)量u2interfacesinterfaces_count;/接口的描述(每個(gè)都是對常量池的引用)u2fields_count;/變量數(shù),包括該類中或接口中類變量和實(shí)例變量field_infofieldsfields_count;/變量表集合u2methods_count;/方法數(shù),包括該類中或接口中定義的所有方法method_infomethodsmethods_count;/方法表集合u2attributes_count;/屬性數(shù),包括InnerClasses,EnclosingMethod,SourceFile等attribute_infoattri
7、butesattributes_count;/屬性表集合注:表本身是一種復(fù)雜結(jié)構(gòu),包含多個(gè)字節(jié),Class文件機(jī)構(gòu)中定義了四種表結(jié)構(gòu),1)常量表2)變量表3)方法表4)屬性表。由于每種表都有一到多個(gè),所以在中可以看出他們都是在數(shù)組中的。接下來我們按順序研究下每個(gè)部分的具體含義!二,常量池Class文件中的常量池大?。╟onstant_pool_count)由第九,第十兩個(gè)字節(jié)(前八個(gè)字節(jié)用來描述版本信息)決定,我們知道兩個(gè)字節(jié)最大可以表示65535,這也就表明一個(gè)Class文件中最多可以具備65535個(gè)常量,包括數(shù)值,字符串,類名,方法名,變量名等等。接下來的constant_pool_cou
8、nt個(gè)字節(jié)就用來描述所有的常量了。為了能表示各種可能類型的值,常量在Class文件中被定義成一種復(fù)雜結(jié)構(gòu):如?1234cp_info/常量表的通用結(jié)構(gòu),不同類型的常量表以此為基礎(chǔ)各不相同u1tag;u1info;可以看出,常量的第一個(gè)字節(jié)表示了該常量的類型。注:constant_pool_count的值為常量個(gè)數(shù)+1,并且常量池常量的索引從1開始!下面為各類型的映射表:Constant TypeValueCONSTANT_Class7CONSTANT_Fieldref9CONSTANT_Methodref10CONSTANT_InterfaceMethodref11CONSTANT_Strin
9、g8CONSTANT_Integer3CONSTANT_Float4CONSTANT_Long5CONSTANT_Double6CONSTANT_NameAndType12CONSTANT_Utf81CONSTANT_MethodHandle15CONSTANT_MethodType16CONSTANT_InvokeDynamic18由上表可以看出,目前為止JVM 一共定義了14種類型的常量。每個(gè)常量表的第一個(gè)字節(jié)表明了常量的類型,那么剩余的值則根據(jù)類型的不同表明了不同的含義,可能是一個(gè)直接值,也可能是一個(gè)對另一個(gè)常量的引用,那么不同類型的常量表定義如下:?12345CONSTANT_Utf8
10、_info/表示Utf8的常量u1tag;/值為1u2length;u1byteslength;Constant_Utf8_info常量用來表示一個(gè)utf8字符串,其長度為可變長度,第一個(gè)字節(jié)的值固定為1(中Constant_Utf8(1),后面兩個(gè)字節(jié)表示了個(gè)字符串的字節(jié)長度length(而不是字符串的長度),然后后面緊跟著的length個(gè)字節(jié)就是字符串的字節(jié)碼了。該常量被引用的頻率頗高,如類名,方法名等常量都引用它。?1234CONSTANT_Class_info/表示類或接口的常量u1tag;/值為7u2name_index;/值為對Constant_Utf8_info常量的引用Cons
11、tant_Class_info常量用來表示一個(gè)類或者接口,一共包含三個(gè)字節(jié),第一個(gè)字節(jié)的值固定為 7(中Constant_Class(7),后兩個(gè)字節(jié)的值為對常量池中另一個(gè)常量(Constant_Utf8_info)的索引,該Constant_Utf8_info常量的值應(yīng)為JVM的內(nèi)部二進(jìn)制類或接口名(binary class or interface name下文詳解)。?1234567891011121314151617CONSTANT_Fieldref_info/表示變量的常量u1tag;/值為9中CONSTANT_Fieldref(9)u2class_index;/值為對Constan
12、t_Class_info常量的索引u2name_and_type_index;/值為CONSTANT_NameAndType_info常量的索引CONSTANT_Methodref_info/表示方法的常量u1tag;/值為10中CONSTANT_Methodref(10)u2class_index;/值為對Constant_Class_info常量的索引u2name_and_type_index;/值為CONSTANT_NameAndType_info常量的索引CONSTANT_InterfaceMethodref_info/表示接口方法的常量u1tag;/值為11中CONSTANT_Int
13、erfaceMethodref(11)u2class_index;/值為對Constant_Class_info常量的索引u2name_and_type_index;/值為CONSTANT_NameAndType_info常量的索引代碼五中的三個(gè)非常相似的常量結(jié)構(gòu)分別表示了變量,方法,接口方法,其中各個(gè)值得含義和大小已在注釋中說明。其實(shí)很容易理解,比如一個(gè)方法,它屬于哪個(gè)類(class_index),它的名字和類型(name_and_type)。?1234CONSTANT_String_info/表示字符串的常量u1tag;/值為8中CONSTANT_String(8)u2string_ind
14、ex;Constant_String_info表示了一個(gè)String類型的常量實(shí)例。一共占用三個(gè)字節(jié),第一個(gè)字節(jié)固定為8,后兩個(gè)字節(jié)為對Constant_Utf8_info常量的索引。?123456789101112131415161718192021CONSTANT_Integer_info/表示int類型數(shù)值的常量u1tag;/值為3中CONSTANT_Integer(3)u4bytes;CONSTANT_Float_info/表示float類型數(shù)值的常量u1tag;/值為4中CONSTANT_Float(4)u4bytes;CONSTANT_Long_info/表示long類型數(shù)值的常量
15、u1tag;/值為5中CONSTANT_Long(5)u4high_bytes;u4low_bytes;CONSTANT_Double_info/表示double類型數(shù)值的常量u1tag;/值為6中CONSTANT_Double(6)u4high_bytes;u4low_bytes;上面四個(gè)常量結(jié)構(gòu)分別表示int, float, long,double類型的常量,比較直觀,不多贅述。?12345CONSTANT_NameAndType_info/用來表示變量,方法名字和類型的常量u1tag;/值為12中CONSTANT_NameAndType(12)u2name_index;/值為對Const
16、ant_Utf8_info常量的引用u2descriptor_index;/值為對Constant_Utf8_info常量的引用Constant_NameAndType_info用來表示變量或者方法的名字和類型的常量,該常量不包含該變量或方法的所屬類或接口的引用,主要用來被Constant_Method_info,Constant_Field_info等常量使用。該常量一共包含五個(gè)字節(jié),第一個(gè)固定為12,第二三個(gè)的值為對Constant_Utf8_info常量的引用,該Constant_Utf8_info常量的值應(yīng)為變量或方法的有效的非限定名(unqualified name下文詳解),第四五
17、的值為對Constant_Utf8_info常量的引用,該Constant_Utf8_info常量的值應(yīng)為有效的變量或方法的描述符(field descriptor,method descriptor下文詳解)。?12345CONSTANT_MethodHandle_info/用來表示方法句柄的常量u1tag;/值為15中CONSTANT_MethodHandle(15)u1reference_kind;/引用類型,值為0-9,表明了該句柄的字節(jié)碼行為u2reference_index;/引用索引Constant_MethodHandle_info常量用來表示方法句柄,第一個(gè)字節(jié)固定為15,第
18、二個(gè)字節(jié)的值為0-9,分別表明了該句柄的不同字節(jié)碼行為,其值的描述見,最后兩個(gè)字節(jié)為對常量池中某常量的引用,但具體引用那種常量由reference_kind而定。 a,如果reference_kind的值為1 (REF_getField), 2 (REF_getStatic), 3 (REF_putField), 或 4 (REF_putStatic),那么reference_index的值為對Constant_Fieldref_info常量的引用,表示該句柄用于的變量。 b,如果reference_kind的值為5 (REF_invokeVirtual), 6 (REF_invokeStat
19、ic), 7 (REF_invokeSpecial), or 8 (REF_newInvokeSpecial),那么reference_index的值為對Constant_Methodref_info常量的引用,表示該句柄所用與的方法或構(gòu)造器。 c,如果reference_kind 的值是9(REF_invokeInterface)時(shí),reference_index的值必須為對Constant_InterfaceMethodref_info常量的引用,表示該句柄所用與的接口方法。 d,如果reference_kind 的值是5 (REF_invokeVirtual), 6 (REF_invok
20、eStatic), 7 (REF_invokeSpecial), or 9 (REF_invokeInterface)時(shí),方法的名字一定不可以為或。 e,如果reference_kind的值是8 (REF_newInvokeSpecial)時(shí),方法的名字必須為。KindDescriptionInterpretation1REF_getFieldgetfield C.f:T2REF_getStaticgetstatic C.f:T3REF_putFieldputfield C.f:T4REF_putStaticputstatic C.f:T5REF_invokeVirtualinvokevirt
21、ual C.m:(A*)T6REF_invokeStaticinvokestatic C.m:(A*)T7REF_invokeSpecialinvokespecial C.m:(A*)T8REF_newInvokeSpecialnew C; dup; invokespecial C.:(A*)void9REF_invokeInterfaceinvokeinterface C.m:(A*)T?1234CONSTANT_MethodType_info/用來表示方法類型的常量u1tag;/值為16,中CONSTANT_MethodType(16)u2descriptor_index;/值為對Cons
22、tant_Utf8_info常量的索引,表示方法的描述符(下文詳解)Constant_MethodType_info常量用來表示方法類型的常量,描述很直觀,不多贅述。?12345CONSTANT_InvokeDynamic_info/該常量用來指定invokedynamic指令的引導(dǎo)方法。u1tag;/值為18,中CONSTANT_InvokeDynamic(18)u2bootstrap_method_attr_index;/值為對屬性表BootstrapMethods的有效引用u2name_and_type_index;/值為對Constant_NameAndType_info常量的引用Co
23、nstant_InvokeDynamic_info常量用來指定invokedynamic指令的引導(dǎo)方法,動(dòng)態(tài)調(diào)用名稱,調(diào)用的參數(shù)和返回值hi,以及一些列可選的引導(dǎo)方法使用的叫做靜態(tài)參數(shù)的常量。三,訪問標(biāo)志位Class文件中緊跟在常量池后的訪問標(biāo)志位,一共占用兩個(gè)字節(jié),也就是十六個(gè)bit位,每個(gè)bit位標(biāo)記一種類的訪問修飾符,如final,abstract,public等,現(xiàn)在JVM已經(jīng)使用了其中的八個(gè),其余八個(gè)保留位未來使用,并且必須置零。八個(gè)標(biāo)志位映射如下表Flag NameValueInterpretationACC_PUBLIC0x0001Declaredpublic; may be a
24、ccessed from outside its package.ACC_FINAL0x0010Declaredfinal; no subclasses allowed.ACC_SUPER0x0020Treat superclass methods specially when invoked by theinvokespecialinstruction.ACC_INTERFACE0x0200Is an interface, not a class.ACC_ABSTRACT0x0400Declaredabstract; must not be instantiated.ACC_SYNTHETI
25、C0x1000Declared synthetic; not present in the source code.ACC_ANNOTATION0x2000Declared as an annotation type.ACC_ENUM0x4000Declared as anenumtype.各個(gè)標(biāo)志位間有一定的約束條件,如ACC_ANNOTATION置位時(shí),ACC_INTERFACE 必須置位等。四,類/父類/接口的描述Class文件中緊跟在訪問標(biāo)志位后的是this_class, super_class, interface_count, interfaces,分別用來表示該類,該類的直接父類
26、(是直接父類哦),實(shí)現(xiàn)的接口數(shù)量,以及接口信息等。A,其中this_class用來表示該類的信息,其值為對常量池中Constant_Class_info常量的引用。B,super_class用來表示該類的直接父類父類信息,其值要么是0要么是對常量池中Constant_Class_info常量的引用。但有以下幾點(diǎn)需要注意:1)如果其值為對常量池Constant_Class_info 的引用,那么被引用的類(直接父類)的ACC_FINAL訪問標(biāo)志位必須不能被置位。2)如果其值為0,那么該類必須,一定是Object類3)接口的super_class值必須是對常量池Constant_Class_inf
27、o常量的引用,并且該常量表示的是Object類。C,interface_count表明了該類實(shí)現(xiàn)接口的數(shù)量,而interfaces表,則表明了所有的實(shí)現(xiàn)接口。其中每一個(gè)interface的值占用兩個(gè)字節(jié),總共占用interface_count * 2個(gè)字節(jié),都是對常量池Constant_Class_info 常量的引用。五,變量表(字段表)接下來緊跟在接口定義后面的是變量個(gè)數(shù)和變量表。該表結(jié)構(gòu)用來描述類中的某個(gè)變量定義,不會(huì)同時(shí)有兩個(gè)名字和描述符都相同的變量。變量的結(jié)構(gòu)描述結(jié)構(gòu)如下?1234567field_infou2access_flags;/訪問標(biāo)志位,跟常量池后用來修飾類的access
28、_flag作用和用法一致u2name_index;/變量名索引,對常量池CONSTANT_Utf8_info常量的索引u2descriptor_index;/變量描述符索引,對常量池CONSTANT_Utf8_info常量的索引u2attributes_count;/屬性數(shù)量attribute_infoattributesattributes_count;/包含的屬性上面的結(jié)構(gòu)便是Class文件中用來描述某個(gè)變量(實(shí)例變量,類變量等)的定義。前三個(gè)u2字節(jié)分別表明了變量的訪問修飾符,名稱和描述符(下文詳解)。其中access_flag 映射如下表Flag NameValueInterpreta
29、tionACC_PUBLIC0x0001Declaredpublic; may be accessed from outside its package.ACC_PRIVATE0x0002Declaredprivate; usable only within the defining class.ACC_PROTECTED0x0004Declaredprotected; may be accessed within subclasses.ACC_STATIC0x0008Declaredstatic.ACC_FINAL0x0010Declaredfinal; never directly ass
30、igned to after object construction (JLS 17.5).ACC_VOLATILE0x0040Declaredvolatile; cannot be cached.ACC_TRANSIENT0x0080Declaredtransient; not written or read by a persistent object manager.ACC_SYNTHETIC0x1000Declared synthetic; not present in the source code.ACC_ENUM0x4000Declared as an element of an
31、enum.名稱和描述符都是對常量池中Constant_Utf8_info常量的索引。以上三個(gè)U2可以描述一個(gè)沒有初始值的變量定義了,如private static int i; 但是如果指定了private static int i = 1;那么則會(huì)用到名為ConstantValue的attribute_info結(jié)構(gòu),下文講解attribute_info時(shí)詳解。變量中的屬性除了ConstantValue外還可能含有Synthetic,Signature,Deprecated,RuntimeVisibleAnnotations和RuntimeInvisibleAnnotations等屬性分別表示
32、該變量是否為編譯器合成的,變量的簽名,是否為廢棄的,運(yùn)行時(shí)可見注解,運(yùn)行時(shí)不可見注解。六,方法表Class文件中跟在變量表后面的是方法個(gè)數(shù)和方法表,該表結(jié)構(gòu)表示一個(gè)方法的定義,其中也會(huì)包括實(shí)例初始化方法(instance initialization method, ),類和接口初始化方法(class or interface initialization method, )。方法表的描述如下?1234567method_infou2access_flags;u2name_index;u2descriptor_index;u2attributes_count;attribute_infoatt
33、ributesattributes_count;該結(jié)構(gòu)跟變量表的結(jié)構(gòu)幾乎完全相同,包括方法的訪問標(biāo)志位,名稱索引,描述符索引等。下表為方法的訪問標(biāo)志位映射Flag NameValueInterpretationACC_PUBLIC0x0001Declaredpublic; may be accessed from outside its package.ACC_PRIVATE0x0002Declaredprivate; accessible only within the defining class.ACC_PROTECTED0x0004Declaredprotected; may be a
34、ccessed within subclasses.ACC_STATIC0x0008Declaredstatic.ACC_FINAL0x0010Declaredfinal; must not be overridden (5.4.5).ACC_SYNCHRONIZED0x0020Declaredsynchronized; invocation is wrapped by a monitor use.ACC_BRIDGE0x0040A bridge method, generated by the compiler.ACC_VARARGS0x0080Declared with variable
35、number of arguments.ACC_NATIVE0x0100Declarednative; implemented in a language other than Java.ACC_ABSTRACT0x0400Declaredabstract; no implementation is provided.ACC_STRICT0x0800Declaredstrictfp; floating-point mode is FP-strict.ACC_SYNTHETIC0x1000Declared synthetic; not present in the source code.不同的
36、是,方法中包含的屬性種類跟變量中的屬性種類有所不同,其中可能包含Code,Exceptions,Synthetic,Signature,Deprecated,RuntimeVisibleAnnotations,RuntimeInvisibleAnnotations,RuntimeVisibleParameterAnnotations,RuntimeInvisibleParameterAnnotations,andAnnotationDefault。其中Code屬性中包含了該方法的方法體(下文詳解)。七,屬性表到目前為止我們已經(jīng)了解了字段表(變量表),方法表,常量池,訪問標(biāo)志位,類的繼承等幾乎全
37、部類的信息在Class文件中的表達(dá)方式了。但是你肯定發(fā)現(xiàn),在方法表中,我們只了解到了方法的名稱,描述符,訪問控制等信息,卻沒有方法體的詳細(xì)描述。不過我們也提到了,方法的方法體是通過屬性表來記錄的。屬性表的結(jié)構(gòu)將在本小結(jié)進(jìn)行較為詳細(xì)的講解。你可能已經(jīng)發(fā)現(xiàn)了,變量表(field_info)方法表(method_info)常量表(cp_info)等結(jié)構(gòu)的頂級結(jié)構(gòu)都是Class文件,換句話說,這些結(jié)構(gòu)都是不可嵌套的。然而你也了解到了,我們接下來講的屬性表結(jié)構(gòu)卻是可以嵌套的,它可以存在在變量表,方法表結(jié)構(gòu)之內(nèi),同樣也可以有類級別的屬性表。屬性表是一類相當(dāng)靈活的結(jié)構(gòu),JVM定義了21種屬性定義,每一種屬性
38、都有自己的結(jié)構(gòu)和用途,有點(diǎn)類似常量池中的常量定義。21種屬性中我們只挑選個(gè)別與與我們關(guān)系比較密切的講解,其它屬性看官可以用同樣的分析方法自行研究了解。?12345attribute_info/屬性表的基本結(jié)構(gòu),不同類型的屬性表以此為基礎(chǔ)各不相同u2attribute_name_index;u4attribute_length;u1infoattribute_length;以上代碼描述了屬性表的結(jié)構(gòu)定義,前兩個(gè)字節(jié)是對常量池中Constant_Utf8_info常量的索引,被索引的常量值為該屬性的名字。中間四個(gè)字節(jié)是屬性內(nèi)容的字節(jié)長度,算下4個(gè)字節(jié)能最多表示多大?2的32次方?不是,虛擬機(jī)規(guī)范中
39、規(guī)定一個(gè)方法不可超過65535個(gè)字節(jié)。最后的attribute_length 個(gè)字節(jié)則是屬性的內(nèi)容,如方法體字節(jié)碼指令集合。前面說了目前JVM預(yù)定義了21種屬性,參照AttributeJava SEclassfileConstantValueCodeStackMapTable650.0ExceptionsInnerClasses1.145.3EnclosingMethod5.049.0Synthetic1.145.3Signature5.049.0SourceFileSourceDebugExtension5.049.0L
40、ineNumberTableLocalVariableTableLocalVariableTypeTable5.049.0Deprecated1.145.3RuntimeVisibleAnnotations5.049.0RuntimeInvisibleAnnotations5.049.0RuntimeVisibleParameterAnnotations5.049.0RuntimeInvisibleParameterAnnotations5.049.0AnnotationDefault5.049.0BootstrapMethods751.0上表可以看出每種屬
41、性的名字和初始版本信息,Java SE7中新加入了BootstrapMethods屬性,invokedynamic指令等實(shí)現(xiàn)動(dòng)態(tài)語言的特性。限于篇幅,我們這里只分析Code,ContantValue屬性。一,ContantValue屬性定義了ContantValue屬性表的結(jié)構(gòu)?12345ConstantValue_attributeu2attribute_name_index;u4attribute_length;u2constantvalue_index;可以看出該屬性是定長的表結(jié)構(gòu),總共有8個(gè)字節(jié)大小。前面講過了前兩部分用來表明屬性的名字和大小,ContantValue屬性表中的name
42、-index索引的常量值固定為“ContantValue”。另外該屬性只會(huì)出現(xiàn)在變量表(field_info)中,用來表示該變量的值。constantvalue_index也是對常量池中某常量的索引,其索引的常量類型根據(jù)變量的類型不同而不同,如下表Field TypeEntry TypelongCONSTANT_LongfloatCONSTANT_FloatdoubleCONSTANT_Doubleint,short,char,byte,booleanCONSTANT_IntegerStringCONSTANT_String二,Code屬性相比ConstantValue屬性,Code屬性相對復(fù)
43、雜些,其結(jié)構(gòu)定義如下?12345678910111213141516Code_attributeu2attribute_name_index;u4attribute_length;u2max_stack;u2max_locals;u4code_length;u1codecode_length;u2exception_table_length;u2start_pc;u2end_pc;u2handler_pc;u2catch_type;exception_tableexception_table_length;u2attributes_count;attribute_infoattributesa
44、ttributes_count;前兩部分與ConstantValue屬性表一樣,表示名字索引和大小,不同的是被索引的名字必須為“Code”。Code屬性只可以出現(xiàn)在方法表(method_info)中,但是如果一個(gè)方法為abstract或者native的,那么其方法表不可以包含Code屬性表。否則必須有且只有一個(gè)屬性表。 1) max_stack:表明方法執(zhí)行的任意時(shí)刻該方法操作數(shù)棧的最大深度。 2) max_locals:表明方法執(zhí)行的任意時(shí)刻該方法的本地變量表中變量的最多個(gè)數(shù)。 關(guān)于操作數(shù)棧,本地變量表等運(yùn)行時(shí)內(nèi)存的相關(guān)知識,下篇文章深入分析。 3) code_length:顧名思義,表明了
45、方法體的字節(jié)碼大小。 4) codecode_length:這里便是所有方法體字節(jié)碼的真正所在地了!JVM規(guī)范對這塊有很長篇幅的約束,如長度大于0小于65535等等已超出本文范圍,不做深究,感興趣可以查看/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.9接下來的兩個(gè)字節(jié)exception_table_length,定義了方法中異常表的個(gè)數(shù)。異常表的結(jié)構(gòu)JVM沒有單獨(dú)定義,而是直接定義在了Code屬性表中,每個(gè)異常表表示一個(gè)異常處理塊,從上面代碼可以看出,每個(gè)異常表有4個(gè)U2字節(jié): 1) start_pc:異
46、常處理塊的開始字節(jié)碼索引(codecode_length中)取值范圍是0, end_pc). 2) end_pc:異常處理塊的結(jié)束字節(jié)碼索引(codecode_length中)取值范圍是(start_pc, code_length).這里有個(gè)有趣的地方,start_pic被定義為inclusive的,就是可以包含第start_pc個(gè)字節(jié)碼, 而end_pc被定義為exclusive的,是不包含第end_pc個(gè)字節(jié)碼的,這樣就有一個(gè)問題,如果代碼長度為65535,并且end_pc也是65535那么最后一個(gè)字節(jié)碼指令就無法被異常處理塊捕獲處理。這是JVM設(shè)計(jì)中的一個(gè)BUG,規(guī)范中已經(jīng)指出。(嚴(yán)謹(jǐn)程
47、度可見一斑) 3) handler_pc:異常處理代碼的字節(jié)碼索引(codecode_length中)。 5) catch_type:捕獲異常的類型,常量池中constant_class_info常量的索引,如果是0則捕獲所有異常。異常表后面是另一個(gè)屬性表的信息了。在Code屬性表中的屬性表(可見屬性表的靈活性了吧)可以是LineNumberTable,LocalVariableTable,LocalVariableTypeTable,andStackMapTable中的一個(gè)或多個(gè),主要提供IDE調(diào)試功能用的。這里我們就不再分析。八,定義到此為止我們整個(gè)Class文件結(jié)構(gòu)已經(jīng)分析的差不多了,相
48、信如果你從頭認(rèn)真閱讀后會(huì)有很大收獲的。但是我們上面還有一個(gè)問題沒有弄明白就是binary class or interface name,unqualified name,descriptor有什么區(qū)別和意義。1)binary class or interface name,在Class文件中一個(gè)類或接口的名字通常都是全限定名(包名+類名),這就稱作binary names。如java.lang.Thread。但是由于當(dāng)年ASCII中點(diǎn)號(.)常被用來表示某些特用意義,因此Java中用斜杠(/)來代替了它,就變成了java/lang/Thread。這就是binary class。2)unqua
49、lified name,Class文件中變量,方法的名字以非限定名的形式保存的,簡單講就是單純的變量名或方法名,是不能包含./;等ASCII字符的。但有個(gè)例外,前者是實(shí)例初始化方法,后者是類初始化方法。3)descriptor,用來描述變量或方法類型的字符串。即用一個(gè)或多個(gè)簡單的字符來表達(dá)Java中的不同類型,其對應(yīng)表如下BaseTypeCharacterTypeInterpretationBbytesigned byteCcharUnicode character code point in the Basic Multilingual Plane, encoded with UTF-16Ddoubledouble-precision floating-point valueFfloatsingle-precision floating-point valueIintintegerJlonglong integerLClassName;referencean instance of classClassNameSshortsigned shortZbooleantrueorfalsereferenceone array dimension對于一個(gè)int類型的變量其descriptor就是 I對于一個(gè)Object類型的變量其descriptor就是Lj
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度教育設(shè)備租賃服務(wù)協(xié)議書3篇
- 2025年度智慧城市基礎(chǔ)設(shè)施場承包建設(shè)合同4篇
- 2025年度旅游度假區(qū)租賃合作協(xié)議4篇
- 二零二五年度草花產(chǎn)業(yè)鏈上下游合作協(xié)議及供應(yīng)鏈管理合同3篇
- 二零二五年度知識產(chǎn)權(quán)行業(yè)勞動(dòng)合同范本3篇
- 二零二五年度航空航天設(shè)備制造承包協(xié)議6篇
- 2025年度農(nóng)產(chǎn)品質(zhì)量安全檢測技術(shù)服務(wù)合同4篇
- 個(gè)人建房承攬協(xié)議實(shí)例版B版
- 2025年度產(chǎn)教融合校企深度合作協(xié)議4篇
- 2025年度企業(yè)培訓(xùn)場地租賃保證金及押金使用合同4篇
- 橫格紙A4打印模板
- CT設(shè)備維保服務(wù)售后服務(wù)方案
- 重癥血液凈化血管通路的建立與應(yīng)用中國專家共識(2023版)
- 兒科課件:急性細(xì)菌性腦膜炎
- 柜類家具結(jié)構(gòu)設(shè)計(jì)課件
- 陶瓷瓷磚企業(yè)(陶瓷廠)全套安全生產(chǎn)操作規(guī)程
- 煤炭運(yùn)輸安全保障措施提升運(yùn)輸安全保障措施
- JTGT-3833-2018-公路工程機(jī)械臺班費(fèi)用定額
- 保安巡邏線路圖
- (完整版)聚乙烯課件
- 建筑垃圾資源化綜合利用項(xiàng)目可行性實(shí)施方案
評論
0/150
提交評論