日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Class 类文件结构

發(fā)布時(shí)間:2024/9/30 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Class 类文件结构 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/ns_code/article/details/17675609

?

平臺(tái)無(wú)關(guān)性

??? Java是與平臺(tái)無(wú)關(guān)的語(yǔ)言,這得益于Java源代碼編譯后生成的存儲(chǔ)字節(jié)碼的文件,即Class文件,以及Java虛擬機(jī)的實(shí)現(xiàn)。不僅使用Java編譯器可以把Java代碼編譯成存儲(chǔ)字節(jié)碼的Class文件,使用JRuby等其他語(yǔ)言的編譯器也可以把程序代碼編譯成Class文件,虛擬機(jī)并不關(guān)心Class的來(lái)源是什么語(yǔ)言,只要它符合一定的結(jié)構(gòu),就可以在Java中運(yùn)行。Java語(yǔ)言中的各種變量、關(guān)鍵字和運(yùn)算符的語(yǔ)義最終都是由多條字節(jié)碼命令組合而成的,因此字節(jié)碼命令所能提供的語(yǔ)義描述能力肯定會(huì)比Java語(yǔ)言本身更強(qiáng)大,這便為其他語(yǔ)言實(shí)現(xiàn)一些有別于Java的語(yǔ)言特性提供了基礎(chǔ),而且這也正是在類加載時(shí)要進(jìn)行安全驗(yàn)證的原因。

?

類文件結(jié)構(gòu)

??? Class文件是一組以8位字節(jié)為基礎(chǔ)單位的二進(jìn)制流,各個(gè)數(shù)據(jù)項(xiàng)目嚴(yán)格按照順序緊湊地排列在Class文件中,中間沒有添加任何分隔符,這使得整個(gè)Class文件中存儲(chǔ)的內(nèi)容幾乎全部都是程序運(yùn)行的必要數(shù)據(jù)。根據(jù)Java虛擬機(jī)規(guī)范的規(guī)定,Class文件格式采用一種類似于C語(yǔ)言結(jié)構(gòu)體的偽結(jié)構(gòu)來(lái)存儲(chǔ),這種偽結(jié)構(gòu)中只有兩種數(shù)據(jù)類型:無(wú)符號(hào)數(shù)和表。無(wú)符號(hào)數(shù)屬于基本數(shù)據(jù)類型,以u(píng)1、u2、u4、u8來(lái)分別代表1、2、4、8個(gè)字節(jié)的無(wú)符號(hào)數(shù)。表是由多個(gè)無(wú)符號(hào)數(shù)或其他表作為數(shù)據(jù)項(xiàng)構(gòu)成的符合數(shù)據(jù)類型,所有的表都習(xí)慣性地以“_info”結(jié)尾。

??? 整個(gè)Class文件本質(zhì)上就是一張表,它由如下所示的數(shù)據(jù)項(xiàng)構(gòu)成。

??? 從表中可以看出,無(wú)論是無(wú)符號(hào)數(shù)還是表,當(dāng)需要描述同一類型但數(shù)量不定的多個(gè)數(shù)據(jù)時(shí),經(jīng)常會(huì)使用一個(gè)前置的容量計(jì)數(shù)器加若干個(gè)連續(xù)的該數(shù)據(jù)項(xiàng)的形式,稱這一系列連續(xù)的摸一個(gè)類型的數(shù)據(jù)為某一類型的集合,比如,fields_count個(gè)field_info表數(shù)據(jù)構(gòu)成了字段表集合。這里需要說明的是:Class文件中的數(shù)據(jù)項(xiàng),都是嚴(yán)格按照上表中的順序和數(shù)量被嚴(yán)格限定的,每個(gè)字節(jié)代表的含義,長(zhǎng)度,先后順序等都不允許改變。

??? 下表列出了Class文件中各個(gè)數(shù)據(jù)項(xiàng)的具體含義:

? ? 從表中可以看出,無(wú)論是無(wú)符號(hào)數(shù)還是表,當(dāng)需要描述同一類型但數(shù)量不定的多個(gè)數(shù)據(jù)時(shí),經(jīng)常會(huì)在其前面使用一個(gè)前置的容量計(jì)數(shù)器來(lái)記錄其數(shù)量,而便跟著若干個(gè)連續(xù)的數(shù)據(jù)項(xiàng),稱這一系列連續(xù)的某一類型的數(shù)據(jù)為某一類型的集合,如:fields_count個(gè)field_info表數(shù)據(jù)便組成了方法表集合。這里需要注意的是:Class文件中各數(shù)據(jù)項(xiàng)是按照上表的順序和數(shù)量被嚴(yán)格限定的,每個(gè)字節(jié)代表的含義、長(zhǎng)度、先后順序都不允許改變。

? ?magic與version

????每個(gè)Class文件的頭4個(gè)字節(jié)稱為魔數(shù)(magic),它的唯一作用是判斷該文件是否為一個(gè)能被虛擬機(jī)接受的Class文件。它的值固定為0xCAFEBABE。緊接著magic的4個(gè)字節(jié)存儲(chǔ)的是Class文件的次版本號(hào)和主版本號(hào),高版本的JDK能向下兼容低版本的Class文件,但不能運(yùn)行更高版本的Class文件。

? ?constant_pool

????major_version之后是常量池(constant_pool)的入口,它是Class文件中與其他項(xiàng)目關(guān)聯(lián)最多的數(shù)據(jù)類型,也是占用Class文件空間最大的數(shù)據(jù)項(xiàng)目之一。

??? 常量池中主要存放兩大類常量:字面量和符號(hào)引用。字面量比較接近于Java層面的常量概念,如文本字符串、被聲明為final的常量值等。而符號(hào)引用總結(jié)起來(lái)則包括了下面三類常量:

  • 類和接口的全限定名(即帶有包名的Class名,如:org.lxh.test.TestClass)
  • 字段的名稱和描述符(private、static等描述符)
  • 方法的名稱和描述符(private、static等描述符)

????虛擬機(jī)在加載Class文件時(shí)才會(huì)進(jìn)行動(dòng)態(tài)連接,也就是說,Class文件中不會(huì)保存各個(gè)方法和字段的最終內(nèi)存布局信息,因此,這些字段和方法的符號(hào)引用不經(jīng)過轉(zhuǎn)換是無(wú)法直接被虛擬機(jī)使用的。當(dāng)虛擬機(jī)運(yùn)行時(shí),需要從常量池中獲得對(duì)應(yīng)的符號(hào)引用,再在類加載過程中的解析階段將其替換為直接引用,并翻譯到具體的內(nèi)存地址中。

??? 這里說明下符號(hào)引用和直接引用的區(qū)別與關(guān)聯(lián):

  • 符號(hào)引用:符號(hào)引用以一組符號(hào)來(lái)描述所引用的目標(biāo),符號(hào)可以是任何形式的字面量,只要使用時(shí)能無(wú)歧義地定位到目標(biāo)即可。符號(hào)引用與虛擬機(jī)實(shí)現(xiàn)的內(nèi)存布局無(wú)關(guān),引用的目標(biāo)并不一定已經(jīng)加載到了內(nèi)存中。
  • 直接引用:直接引用可以是直接指向目標(biāo)的指針、相對(duì)偏移量或是一個(gè)能間接定位到目標(biāo)的句柄。直接引用是與虛擬機(jī)實(shí)現(xiàn)的內(nèi)存布局相關(guān)的,同一個(gè)符號(hào)引用在不同虛擬機(jī)實(shí)例上翻譯出來(lái)的直接引用一般不會(huì)相同。如果有了直接引用,那說明引用的目標(biāo)必定已經(jīng)存在于內(nèi)存之中了。

??? 常量池中的每一項(xiàng)常量都是一個(gè)表,共有11種(JDK1.7之前)結(jié)構(gòu)各不相同的表結(jié)構(gòu)數(shù)據(jù),沒中表開始的第一位是一個(gè)u1類型的標(biāo)志位(1-12,缺少2),代表當(dāng)前這個(gè)常量屬于的常量類型。11種常量類型所代表的具體含義如下表所示:

??? 這11種常量類型各自均有自己的結(jié)構(gòu)。在CONSTANT_Class_info型常量的結(jié)構(gòu)中有一項(xiàng)name_index屬性,該常屬性中存放一個(gè)索引值,指向常量池中一個(gè)CONSTANT_Utf8_info類型的常量,該常量中即保存了該類的全限定名字符串。而CONSTANT_Fieldref_info、CONSTANT_Methodref_info、CONSTANT_InterfaceMethodref_info型常量的結(jié)構(gòu)中都有一項(xiàng)index屬性,存放該字段或方法所屬的類或接口的描述符CONSTANT_Class_info的索引項(xiàng)。另外,最終保存的諸如Class名、字段名、方法名、修飾符等字符串都是一個(gè)CONSTANT_Utf8_info類型的常量,也因此,Java中方法和字段名的最大長(zhǎng)度也即是CONSTANT_Utf8_info型常量的最大長(zhǎng)度,在CONSTANT_Utf8_info型常量的結(jié)構(gòu)中有一項(xiàng)length屬性,它是u2類型的,即占用2個(gè)字節(jié),那么它的最大的length即為65535。因此,Java程序中如果定義了超過64KB英文字符的變量或方法名,將會(huì)無(wú)法編譯。

???下表給出了常量池中11種數(shù)據(jù)類型的結(jié)構(gòu):

? ? 常量

項(xiàng)目

? 類型 ?

描述

?

CONSTANT_Utf8_info

tag

u1

值為1

length

u2

UF-8編碼的字符串占用的字節(jié)數(shù)

bytes

u1

長(zhǎng)度為length的UTF-8編碼的字符串

?

CONSTANT_Integer_info

tag

u1

值為3

bytes

u4

按照高位在前存儲(chǔ)的int值

?

CONSTANT_Float_info

tag

u1

值為4

bytes

u4

按照高位在前存儲(chǔ)的float值

?

CONSTANT_Long_info

tag

u1

值為5

bytes

u8

按照高位在前存儲(chǔ)的long值

?

CONSTANT_Double_info

tag

u1

值為6

bytes

u8

按照高位在前存儲(chǔ)的double值

?

CONSTANT_Class_info

tag

u1

值為7

index

u2

指向全限定名常量項(xiàng)的索引

?

CONSTANT_String_info

tag

u1

值為8

index

u2

指向字符串字面量的索引

?

CONSTANT_Fieldref_info

tag

u1

值為9

index

u2

指向聲明字段的類或接口描述符CONSTANT_Class_info的索引項(xiàng)

index

u2

指向字段名稱及類型描述符CONSTANT_NameAndType_info的索引項(xiàng)

?

CONSTANT_Methodref_info

tag

u1

值為10

index

u2

指向聲明方法的類描述符CONSTANT_Class_info的索引項(xiàng)

index

u2

指向方法名稱及類型描述符CONSTANT_NameAndType_info的索引項(xiàng)

?

CONSTANT_InrerfaceMethodref_info

tag

u1

值為11

index

u2

指向聲明方法的接口描述符CONSTANT_Class_info的索引項(xiàng)

index

u2

指向方法名稱及類型描述符CONSTANT_NameAndType_info的索引項(xiàng)

?

CONSTANT_NameAndType_info

tag

u1

值為12

index

u2

指向字段或方法名稱常量項(xiàng)目的索引

index

u2

指向該字段或方法描述符常量項(xiàng)的索引

??? access_flag

??? 在常量池結(jié)束之后,緊接著的2個(gè)字節(jié)代表訪問標(biāo)志(access_flag),這個(gè)標(biāo)志用于識(shí)別一些類或接口層次的訪問信息,包括:這個(gè)Class是類還是接口,是否定義為public類型,abstract類型,如果是類的話,是否聲明為final,等等。每種訪問信息都由一個(gè)十六進(jìn)制的標(biāo)志值表示,如果同時(shí)具有多種訪問信息,則得到的標(biāo)志值為這幾種訪問信息的標(biāo)志值的邏輯或。

???this_class、super_class、interfaces

??? 類索引(this_class)和父類索引(super_class)都是一個(gè)u2類型的數(shù)據(jù),而接口索引集合(interfaces)則是一組u2類型的數(shù)據(jù)集合,Class文件中由這三項(xiàng)數(shù)據(jù)來(lái)確定這個(gè)類的繼承關(guān)系。類索引、父類索引和接口索引集合都按照順序排列在訪問標(biāo)志之后,類索引和父類索引兩個(gè)u2類型的索引值表示,它們各自指向一個(gè)類型為COMNSTANT_Class_info的類描述符常量,通過該常量中的索引值找到定義在COMNSTANT_Utf8_info類型的常量中的全限定名字符串。而接口索引集合就用來(lái)描述這個(gè)類實(shí)現(xiàn)了哪些接口,這些被實(shí)現(xiàn)的接口將按implements語(yǔ)句(如果這個(gè)類本身是個(gè)接口,則應(yīng)當(dāng)是extend語(yǔ)句)后的接口順序從左到右排列在接口的索引集合中。

??? fields

??? 字段表(field_info)用于描述接口或類中聲明的變量。字段包括了類級(jí)變量或?qū)嵗?jí)變量,但不包括在方法內(nèi)聲明的變量。字段的名字、數(shù)據(jù)類型、修飾符等都是無(wú)法固定的,只能引用常量池中的常量來(lái)描述。下面是字段表的最種格式:

?

??? 其中的access_flags與類中的access_flagsfei類似,是表示數(shù)據(jù)類型的修飾符,如public、static、volatile等。后面的name_index和descriptor_index都是對(duì)常量池的引用,分別代表字段的簡(jiǎn)單名稱及字段和方法的描述符。這里簡(jiǎn)單解釋下“簡(jiǎn)單名稱”、“描述符”和“全限定名”這三種特殊字符串的概念。

??? 前面有所提及,全限定名即指一個(gè)事物的完整的名稱,如在org.lxh.test包下的TestClass類的全限定名為:org/lxh/test/TestClass,即把包名中的“.”改為“/”,為了使連續(xù)的多個(gè)全限定名之間不產(chǎn)生混淆,在使用時(shí)最后一般會(huì)加入一個(gè)“,”來(lái)表示全限定名結(jié)束。簡(jiǎn)單名稱則是指沒有類型或參數(shù)修飾的方法或字段名稱,如果一個(gè)類中有這樣一個(gè)方法boolean? get(int name)和一個(gè)變量private final static int m,則他們的簡(jiǎn)單名稱則分別為get()和m。

??? 而描述符的作用則是用來(lái)描述字段的數(shù)據(jù)類型、方法的參數(shù)列表(包括數(shù)量、類型以及順序等)和返回值的。根據(jù)描述符規(guī)則,詳細(xì)的描述符標(biāo)示字的含義如下表所示:

?

??? 對(duì)于數(shù)組類型,每一維度將使用一個(gè)前置的“[”字符來(lái)描述,如一個(gè)整數(shù)數(shù)組“int [][]”將為記錄為“[[I”,而一個(gè)String類型的數(shù)組“String[]”將被記錄為“[Ljava/lang/String”

??? 用方法描述符描述方法時(shí),按照先參數(shù)后返回值的順序描述,參數(shù)要按照嚴(yán)格的順序放在一組小括號(hào)內(nèi),如方法 int getIndex(String name,char[] tgc,int start,int end,char target)的描述符為“(Ljava/lang/String[CIIC)I”。

??? 字段表包含的固定數(shù)據(jù)項(xiàng)目到descriptor_index為止就結(jié)束了,但是在它之后還緊跟著一個(gè)屬性表集合用于存儲(chǔ)一些額外的信息。比如,如果在類中有如下字段的聲明:staticfinalint m = 2;那就可能會(huì)存在一項(xiàng)名為ConstantValue的屬性,它指向常量2。關(guān)于attribute_info的詳細(xì)內(nèi)容,在后面關(guān)于屬性表的項(xiàng)目中會(huì)有詳細(xì)介紹。

??? 最后需要注意一點(diǎn):字段表集合中不會(huì)列出從父類或接口中繼承而來(lái)的字段,但有可能列出原本Java代碼中不存在的字段。比如在內(nèi)部類中為了保持對(duì)外部類的訪問性,會(huì)自動(dòng)添加指向外部類實(shí)例的字段。

??? methods

??? 方法表(method_info)的結(jié)構(gòu)與屬性表的結(jié)構(gòu)相同,不過多贅述。方法里的Java代碼,經(jīng)過編譯器編譯成字節(jié)碼指令后,存放在方法屬性表集合中一個(gè)名為“Code”的屬性里,關(guān)于屬性表的項(xiàng)目,同樣會(huì)在后面詳細(xì)介紹。

??? 與字段表集合相對(duì)應(yīng),如果父類方法在子類中沒有被覆寫,方法表集合中就不會(huì)出現(xiàn)來(lái)自父類的方法信息。但同樣,有可能會(huì)出現(xiàn)由編譯器自動(dòng)添加的方法,最典型的便是類構(gòu)造器“<clinit>”方法和實(shí)例構(gòu)造器“<init>”方法。

??? 在Java語(yǔ)言中,要重載一個(gè)方法,除了要與原方法具有相同的簡(jiǎn)單名稱外,還要求必須擁有一個(gè)與原方法不同的特征簽名,特征簽名就是一個(gè)方法中各個(gè)參數(shù)在常量池中的字段符號(hào)引用的集合,也就是因?yàn)榉祷刂挡粫?huì)包含在特征簽名之中,因此Java語(yǔ)言里無(wú)法僅僅依靠返回值的不同來(lái)對(duì)一個(gè)已有方法進(jìn)行重載。

??? attributes

??? 屬性表(attribute_info)在前面已經(jīng)出現(xiàn)過多系,在Class文件、字段表、方法表中都可以攜帶自己的屬性表集合,以用于描述某些場(chǎng)景專有的信息。

????屬性表集合的限制沒有那么嚴(yán)格,不再要求各個(gè)屬性表具有嚴(yán)格的順序,并且只要不與已有的屬性名重復(fù),任何人實(shí)現(xiàn)的編譯器都可以向?qū)傩员碇袑懭胱约憾x的屬性信息,但Java虛擬機(jī)運(yùn)行時(shí)會(huì)忽略掉它不認(rèn)識(shí)的屬性。Java虛擬機(jī)規(guī)范中預(yù)定義了9項(xiàng)虛擬機(jī)應(yīng)當(dāng)能識(shí)別的屬性(JDK1.5后又增加了一些新的特性,因此不止下面9項(xiàng),但下面9項(xiàng)是最基本也是必要,出現(xiàn)頻率最高的),如下表所示:

??? 對(duì)于每個(gè)屬性,它的名稱都需要從常量池中引用一個(gè)CONSTANT_Utf8_info類型的常量來(lái)表示,每個(gè)屬性值的結(jié)構(gòu)是完全可以自定義的,只需說明屬性值所占用的位數(shù)長(zhǎng)度即可。一個(gè)符合規(guī)則的屬性表至少應(yīng)具有“attribute_name_info”、“attribute_length”和至少一項(xiàng)信息屬性。

??? 1)Code屬性

??? 前面已經(jīng)說過,Java程序方法體中的代碼講過Javac編譯后,生成的字節(jié)碼指令便會(huì)存儲(chǔ)在Code屬性中,但并非所有的方法表都必須存在這個(gè)屬性,比如接口或抽象類中的方法就不存在Code屬性。如果方法表有Code屬性存在,那么它的結(jié)構(gòu)將如下表所示:

??? attribute_name_index是一項(xiàng)指向CONSTANT_Utf8_info型常量的索引,常量值固定為“Code”,它代表了該屬性的名稱。attribute_length指示了屬性值的長(zhǎng)度,由于屬性名稱索引與屬性長(zhǎng)度一共是6個(gè)字節(jié),所以屬性值的長(zhǎng)度固定為整個(gè)屬性表的長(zhǎng)度減去6個(gè)字節(jié)。

??? max_stack代表了操作數(shù)棧深度的最大值,max_locals代表了局部變量表所需的存儲(chǔ)空間,它的單位是Slot,并不是在方法中用到了多少個(gè)局部變量,就把這些局部變量所占Slot之和作為max_locals的值,原因是局部變量表中的Slot可以重用。

??? code_length和code用來(lái)存儲(chǔ)Java源程序編譯后生成的字節(jié)碼指令。code用于存儲(chǔ)字節(jié)碼指令的一系列字節(jié)流,它是u1類型的單字節(jié),因此取值范圍為0x00到0xFF,那么一共可以表達(dá)256條指令,目前,Java虛擬機(jī)規(guī)范已經(jīng)定義了其中200條編碼值對(duì)應(yīng)的指令含義。code_length雖然是一個(gè)u4類型的長(zhǎng)度值,理論上可以達(dá)到2^32-1,但是虛擬機(jī)規(guī)范中限制了一個(gè)方法不允許超過65535條字節(jié)碼指令,如果超過了這個(gè)限制,Javac編譯器將會(huì)拒絕編譯。

??? 字節(jié)碼指令之后是這個(gè)方法的顯式異常處理表集合(exception_table),它對(duì)于Code屬性來(lái)說并不是必須存在的。它的格式如下表所示:

??? 它包含四個(gè)字段,這些字段的含義為:如果字節(jié)碼從第start_pc行到第end_pc行之間(不含end_pc行)出現(xiàn)了類型為catch_type或其子類的異常(catch_type為指向一個(gè)CONSTANT_Class_info型常量的索引),則轉(zhuǎn)到第handler_pc行繼續(xù)處理,當(dāng)catch_pc的值為0時(shí),代表人和的異常情況都要轉(zhuǎn)到handler_pc處進(jìn)行處理。異常表實(shí)際上是Java代碼的一部分,編譯器使用異常表而不是簡(jiǎn)單的跳轉(zhuǎn)命令來(lái)實(shí)現(xiàn)Java異常即finally處理機(jī)制,也因此,finally中的內(nèi)容會(huì)在try或catch中的return語(yǔ)句之前執(zhí)行,并且在try或catch跳轉(zhuǎn)到finally之前,會(huì)將其內(nèi)部需要返回的變量的值復(fù)制一份副本到最后一個(gè)本地表量表的Slot中,也因此便有了http://blog.csdn.net/ns_code/article/details/17485221這篇文章中出現(xiàn)的情況。

??? Code屬性是Class文件中最重要的一個(gè)屬性,如果把一個(gè)Java程序中的信息分為代碼和元數(shù)據(jù)兩部分,那么在整個(gè)Class文件里,Code屬性用于描述代碼,所有的其他數(shù)據(jù)項(xiàng)目都用于描述元數(shù)據(jù)。

??? 2)Exception屬性

??? 這里的Exception屬性的作用是列舉出方法中可能拋出的受查異常,也就是方法描述時(shí)在throws關(guān)鍵字后面列舉的異常。它的結(jié)構(gòu)很簡(jiǎn)單,只有attribute_name_index、attribute_length、number_of_exceptions、exception_index_table四項(xiàng),從字面上便很容易理解,這里不再詳述。

??? 3)LineNumberTable屬性

??? 它用于描述Java源碼行號(hào)與字節(jié)碼行號(hào)之間的對(duì)應(yīng)關(guān)系。

??? 4)LocalVariableTable屬性

??? 它用于描述棧幀中局部變量表中的變量與Java源碼中定義的變量之間的對(duì)應(yīng)關(guān)系。

??? 5)SourceFile屬性

??? 它用于記錄生成這個(gè)Class文件的源碼文件名稱。

??? 6)ConstantValue屬性

??? ConstantValue屬性的作用是通知虛擬機(jī)自動(dòng)為靜態(tài)變量賦值,只有被static修飾的變量才可以使用這項(xiàng)屬性。在Java中,對(duì)非static類型的變量(也就是實(shí)例變量)的賦值是在實(shí)例構(gòu)造器<init>方法中進(jìn)行的;而對(duì)于類變量(static變量),則有兩種方式可以選擇:在類構(gòu)造其中賦值,或使用ConstantValue屬性賦值。

??? 目前Sun Javac編譯器的選擇是:如果同時(shí)使用final和static修飾一個(gè)變量(即全局常量),并且這個(gè)變量的數(shù)據(jù)類型是基本類型或String的話,就生成ConstantValue屬性來(lái)進(jìn)行初始化(編譯時(shí)Javac將會(huì)為該常量生成ConstantValue屬性,在類加載的準(zhǔn)備階段虛擬機(jī)便會(huì)根據(jù)ConstantValue為常量設(shè)置相應(yīng)的值),如果該變量沒有被final修飾,或者并非基本類型及字符串,則選擇在<clinit>方法中進(jìn)行初始化。

??? 雖然有final關(guān)鍵字才更符合”ConstantValue“的含義,但在虛擬機(jī)規(guī)范中并沒有強(qiáng)制要求字段必須用final修飾,只要求了字段必須用static修飾,對(duì)final關(guān)鍵字的要求是Javac編譯器自己加入的限制。因此,在實(shí)際的程序中,只有同時(shí)被final和static修飾的字段才有ConstantValue屬性。而且ConstantValue的屬性值只限于基本類型和String,很明顯這是因?yàn)樗鼜某A砍刂幸仓荒軌蛞玫交绢愋秃蚐tring類型的字面量。

??? 下面簡(jiǎn)要說明下final、static、static final修飾的字段賦值的區(qū)別:

  • static修飾的字段在類加載過程中的準(zhǔn)備階段被初始化為0或null等默認(rèn)值,而后在初始化階段(觸發(fā)類構(gòu)造器<clinit>)才會(huì)被賦予代碼中設(shè)定的值,如果沒有設(shè)定值,那么它的值就為默認(rèn)值。
  • final修飾的字段在運(yùn)行時(shí)被初始化(可以直接賦值,也可以在實(shí)例構(gòu)造器中賦值),一旦賦值便不可更改;
  • static final修飾的字段在Javac時(shí)生成ConstantValue屬性,在類加載的準(zhǔn)備階段根據(jù)ConstantValue的值為該字段賦值,它沒有默認(rèn)值,必須顯式地賦值,否則Javac時(shí)會(huì)報(bào)錯(cuò)。可以理解為在編譯期即把結(jié)果放入了常量池中。

??? 7)InnerClasses屬性

??? 該屬性用于記錄內(nèi)部類與宿主類之間的關(guān)聯(lián)。如果一個(gè)類中定義了內(nèi)部類,那么編譯器將會(huì)為它及它所包含的內(nèi)部類生成InnerClasses屬性。

??? 8)Deprecated屬性和Synthetic屬性

??? 該屬性用于表示某個(gè)類、字段和方法,已經(jīng)被程序作者定為不再推薦使用,它可以通過在代碼中使用@Deprecated注釋進(jìn)行設(shè)置。

??? 9)Synthetic屬性

??? 該屬性代表此字段或方法并不是Java源代碼直接生成的,而是由編譯器自行添加的,如this字段和實(shí)例構(gòu)造器、類構(gòu)造器等。

?

?

?

總結(jié)

以上是生活随笔為你收集整理的Class 类文件结构的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。