這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)深入淺析Java中class文件格式的屬性,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
積石山保安族東鄉(xiāng)族網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項目制作,到程序開發(fā),運(yùn)營維護(hù)。創(chuàng)新互聯(lián)成立于2013年到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運(yùn)維經(jīng)驗,來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
class文件中的attributes_count和attributes
attributes_count位于class文件中methods的下面。 它占兩個字節(jié), 存儲的是一個整數(shù)值, 表示class文件中屬性的個數(shù)。
attributes_count下面的是attributes, 可以把它看做一個數(shù)組, 每個數(shù)組項是一個attribute_info , 每個attribute_info 表示一個屬性。attributes中有 attributes_count個attribute_info 。
需要說明的是, 屬性會出現(xiàn)在多個地方, 不僅僅出現(xiàn)在頂層的ClassFile中, 也會出現(xiàn)在class文件中的數(shù)據(jù)項中, 如出現(xiàn)在field_info中, 用來描述特定字段的一些信息, 還可以出現(xiàn)在method_info中, 用來描述特定方法的一些信息。
屬性(attribute_info)的大概格式是這樣的:
其中attribute_name_index占兩個字節(jié), 它是一個指向常量池數(shù)據(jù)項的索引。 它指向一個CONSTANT_Utf8_info , 這個CONSTANT_Utf8_info 中存放的是當(dāng)前屬性的名字。
attribute_name_index下面的四個字節(jié)叫做attribute_length, 它表示當(dāng)前屬性的長度, 這個長度不包括前6個字節(jié), 也就是說只包括屬性真實(shí)信息(也就是info)的長度。
attribute_length下面的數(shù)據(jù)是info, 它的長度由上面提到的attribute_length指定, 它存放的是真實(shí)的屬性數(shù)據(jù)。
下面我們會依次介紹一些重要屬性, 相對不是很重要的屬性會一筆帶過。
ClassFile中的SourceFile屬性
首先介紹一個比較簡單的屬性:SourceFile。 該屬性出現(xiàn)在頂層的class文件中。 它描述了該類是從哪個源文件中編譯來的, 注意, 描述的是源文件, 而不是類, 一個源文件中可以存在多個類。 它的格式如下:
前面說過, attribute_name_index指向常量池中的一個CONSTANT_Utf8_info , 這個CONSTANT_Utf8_info 中存放的是這個屬性的名字字符串, 即“SourceFile” 。
attribute_length是屬性信息的長度, 這里是2, 因為這個屬性的info就兩個字節(jié)。
sourcefile_index占兩個字節(jié), 這也是為什么attribute_length是2的原因。 sourcefile_index指向常量池中的一個CONSTANT_Utf8_info , 這個CONSTANT_Utf8_info 中存放的是生成該類的源文件的文件名, 這里的文件名不包括路徑部分。
下面舉例說明, 示例代碼:
package combjpowernodetest; public class Person { int age; int getAge(){ return age; } }
反編譯后的相關(guān)信息:
public class combjpowernodetestPerson SourceFile: "Personjava" Constant pool: ......... #20 = Utf8 SourceFile #21 = Utf8 Personjava .........
反編譯結(jié)果中的 SourceFile: "Person.java" 一行是SourceFile屬性的簡單表示形式。 可以把它看做一個可讀的attribute_info 。 下面常量池中的第20項的CONSTANT_Utf8_info是對這個屬性的屬性名(attribute_name_index)的描述 , 第21項的CONSTANT_Utf8_info是對源文件的文件名的描述。
下面是圖例, 注意, 虛線范圍內(nèi)表示常量池區(qū)域:
ClassFile中的InnerClasses屬性
InnerClasses是一個存在于頂層class文件中的屬性, 它描述的是內(nèi)部類和外圍類的關(guān)系。 這是一個相對來說比較復(fù)雜的屬性, 因為每個類可能有多個內(nèi)部類, 而這些內(nèi)部類中可能還有內(nèi)部類, 多層嵌套。外圍類中的InnerClasses屬性必須描述它的所有內(nèi)部類, 而內(nèi)部類中的InnerClasses也必須描述它的外圍類。
由于這個屬性相對較為復(fù)雜, 而對于我們理解class文件又不具有很大的意義, 所以我們只是簡單的介紹一下。 如果想深入理解這個屬性, 請參考 《深入Java虛擬機(jī)》 第144到166頁。
下面是這個屬性的結(jié)構(gòu):
attribute_name_index和attribute_length就不過多介紹了, 和上面介紹的是一樣的。
number_of_classes描述的是內(nèi)部類的個數(shù)。
classes可以看做是一個數(shù)組, 這個數(shù)組中的每一項是一個inner_class_info, 而每個inner_class_info是對一個內(nèi)部類的描述。每個 inner_class_info的結(jié)構(gòu)如下:
Synthetic屬性
Synthetic屬性可以出現(xiàn)在filed_info中, method_info中和頂層的ClassFile中, 分別表示這個字段, 方法或類不是有用戶代碼生成的(即不存在與源文件中), 而是由編譯器自動添加的。 例如, 編譯器會為內(nèi)部類增加一個字段, 該字段是對外部類對象的引用; 如果一個不定義構(gòu)造方法, 那么編譯器會自動添加一個無參數(shù)的構(gòu)造方法<init>, 如果定義了靜態(tài)字段或靜態(tài)代碼塊, 還會根據(jù)具體情況, 增加靜態(tài)初始化方法<clinit> 。 此外, 有些機(jī)制, 如動態(tài)代理, 會在運(yùn)行時自動生成字節(jié)碼文件, 由于這些類不是由源文件中編譯來的, 所以這些類的class文件中會有一個Synthetic屬性。
它的結(jié)構(gòu)如下:
可以看到, 它沒有真正的屬性數(shù)據(jù)info, 它只是一個標(biāo)志性的屬性, 用來表示它所在的字段, 方法或類是由編譯器自動添加的 。
下面以實(shí)例代碼來說明, 源碼如下:
package combjpowernodetest; public class Person { static{ Systemoutprintln("static"); } int age; int getAge(){ return age; } }
反編譯后的相關(guān)信息如下:
{ int age; flags: static {}; ......... public combjpowernodetestPerson(); ......... int getAge(); ......... }
由反編譯結(jié)果可以看出, 編譯器自動生成了靜態(tài)初始化方法和構(gòu)造方法。 可能是因為Synthetic屬性是可選的(也就是說某個版本的編譯器可以選擇不加入Synthetic屬性) ,所以在反編譯后的結(jié)果中沒有發(fā)現(xiàn)Synthetic屬性。
ConstantValue屬性
ConstantValue屬性出現(xiàn)在class文件中的field_info中, 也就是說它是一個和字段相關(guān)的屬性。 每個field_info中最多只能出現(xiàn)一個ConstantValue屬性。 此外, 要注意的是, 必須是靜態(tài)字段才可以有ConstantValue屬性。 這個靜態(tài)字段可以是final的, 也可以不是final的。
這個屬性為靜態(tài)變量提供了另一種初始化的方式。 靜態(tài)變量初始化的方式有兩種, 一種就是現(xiàn)在要講得ConstantValue屬性, 另一種就是靜態(tài)初始化方法<clinit> 不同的編譯器和虛擬機(jī)可以有不同的實(shí)現(xiàn)方式。 但是如果虛擬機(jī)決定使用ConstantValue屬性為靜態(tài)變量賦值, 那么為這個變量的賦值動作, 必須位于執(zhí)行<clinit>方法之前。
此外, 只有基本數(shù)據(jù)類型或String類型的靜態(tài)變量才可以存在ConstantValue屬性, 原因在下面會有說明。
下面介紹它的結(jié)構(gòu):
attribute_name_index和attribute_length就不過多介紹了, 和上面介紹的是一樣的。這里的attribute_length為2 。
位于attribute_length之下的是constantvalue_index , 這是一個指向常量池中某個數(shù)據(jù)項的索引。這個常量池數(shù)據(jù)項中存放的就是當(dāng)前字段的值。
這個常量池中的數(shù)據(jù)項,根據(jù)field_info描述的字段的不同, 可以是不同類型的數(shù)據(jù)項, 如果當(dāng)前字段是byte, short, char, int, boolean類型, 那么這個被指向的常量池數(shù)據(jù)項就會是一個CONSTANT_Integer_info , 如果當(dāng)前字段是一個long類型的字段, 那么這個被指向的常量池數(shù)據(jù)項就會是一個CONSTANT_Long_info 。 如果當(dāng)前字段是是一個String類型的字段 , 那么這個被指向的常量池數(shù)據(jù)項就是一個CONSTANT_String_info 。 這里有一點(diǎn)需要說明, 雖然java語言支持byte, short, char, boolean類型, 但是JVM卻不支持這幾種類型, 表現(xiàn)在class文件中就是, class文件中的常量池中沒有和這幾個數(shù)據(jù)類型相對應(yīng)的數(shù)據(jù)項, 這幾中類型都被JVM在執(zhí)行時當(dāng)做int來對待, 表現(xiàn)在class文件中就是, 這幾種類型都對應(yīng)常量池中的CONSTANT_Integer_info 數(shù)據(jù)項。
這也說明了, 為什么只有基本數(shù)據(jù)類型和String類型的靜態(tài)常量才會存在ConstantValue屬性 。 因為constantvalue_index只是一個指向常量池的索引, 而其他引用類型的常量不會存在于常量池中。
下面以實(shí)例來說明, 實(shí)例代碼如下:
package combjpowernodetest; public class Person { static final int a = 1; int age; int getAge(){ return age; } }
反編譯后的相關(guān)結(jié)果如下:
...... Constant pool: #7 = Utf8 ConstantValue #8 = Integer 1 { static final int a; flags: ACC_STATIC, ACC_FINAL ConstantValue: int 1 ......... }
可以看到, 源文件中的a字段, 是static final 的, 所以編譯器為這個字段的filed_info生成了ConstantValue屬性。 這個屬性的示意圖如下所示, 注意, 虛線范圍內(nèi)表示常量池區(qū)域:
Deprecated屬性
Deprecated屬性可以存在于filed_info中, method_info中和頂層的ClassFile中, 分別表示這個字段, 方法或類已經(jīng)過時。 這個屬性用來支持源文件中的@deprecated注解。 也就是說, 如果在源文件中為一個字段, 方法或類標(biāo)注了@deprecated注解, 那么編譯器就會在class文件中為這個字段, 方法或類生成一個Deprecated屬性 。
Deprecated屬性的格式如下:
和上面的屬性一樣, attribute_name_index屬性指向一個常量池中的CONSTANT_Utf8_info 。 這個CONSTANT_Utf8_info中存放著該屬性的名字 “Deprecated” 。
attribute_length永遠(yuǎn)為0 , 因為這個屬性只是一個標(biāo)志信息, 用來表示字段, 方法, 類已經(jīng)過時, 而不具有任何實(shí)質(zhì)性的屬性信息。
下面以代碼示例來說明, 代碼如下:
package combjpowernodetest; public class Person { int age; @Deprecated int getAge(){ return age; } }
在getAge方法上使用了@deprecated 。 下面是反編譯之后的相關(guān)信息:
...... nstant pool: ...... #18 = Utf8 Deprecated ...... ...... int getAge(); flags: Deprecated: true ......
可以看到, 在getAge方法相關(guān)的信息中, 有一行 Deprecated: true , 這說明編譯器在getAge方法的method_info中加入了Deprecated屬性。 常量池第18項的CONSTANT_Utf8_info中存放的是Deprecated屬性的屬性名“Deprecated” 。
下面是示意圖, 虛線范圍內(nèi)表示常量池區(qū)域:
上述就是小編為大家分享的深入淺析Java中class文件格式的屬性了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
網(wǎng)站題目:深入淺析Java中class文件格式的屬性
URL網(wǎng)址:http://aaarwkj.com/article42/jjgphc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營銷、網(wǎng)站收錄、網(wǎng)站設(shè)計、網(wǎng)站建設(shè)、品牌網(wǎng)站設(shè)計、軟件開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)