JVM - 類文件結構

1. Class文件數(shù)據(jù)類型

根據(jù)Java虛擬機規(guī)范規(guī)定伸辟,Class文件格式采用一種類似于C語言結構體的偽結構來存儲數(shù)據(jù),這種偽結構只有兩種數(shù)據(jù)類型:無符號數(shù)

無符號數(shù)

無符號數(shù)屬于基本的數(shù)據(jù)類型归露,可以用來描述數(shù)字币砂、索引引用、數(shù)量值或者按照UTF-8編碼構成字符串值囤耳。

標記 含義
u1 1個字節(jié)無符號數(shù)
u2 2個字節(jié)無符號數(shù)
u4 4個字節(jié)無符號數(shù)
u8 8個字節(jié)無符號數(shù)

表是由多個無符號數(shù)或者其他表作為數(shù)據(jù)項構成的復合數(shù)據(jù)類型驱闷,所有表都習慣性地以“_info”結尾耻台。表用于描述有層次關系的復合結構的數(shù)據(jù),整個Class文件本質上就是一張表空另。

2. Class文件結構

每一個Class文件對應于一個如下所示的ClassFile結構體盆耽。

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];
}

2.1. 魔數(shù)

每個Class文件的頭4個字節(jié)稱為魔數(shù)(Magic Number),它的唯一作用是確定這個文件是否為一個能被虛擬機接受的Class文件扼菠。

2.2. 版本號

緊接著魔數(shù)的4個字節(jié)存儲的是Class文件的版本號:
第5和第6個字節(jié)是次版本號(Minor Version)
第7和第8個字節(jié)是主版本號(Major Version)

2.3. 常量池(cp_info)

常量池中包含了與文件中類和接口相關的常量摄杂。
常量池中主要存放兩大類常量:字面量(Literal)符號引用(Symbolic References)

2.3.1. 字面量

文本字符串循榆、聲明為final的常量值等析恢。

2.3.2. 符號引用

符號引用屬于編譯原理方面的改了,包括下面三類常量:

  • 類和接口的全限定名(Fully Qualified Name)
  • 字段的名稱和描述符(Descriptor)
  • 方法的名稱和描述符

全限定名
當常量池入口指向類或接口時秧饮,它們給出該類或者接口的全限定名映挂。在class文件中,全限定名的點用斜線取代了盗尸。例如柑船,在class文件中,java.lang.Object的全限定名表示為java/lang/Object; 在class文件中泼各,java.util.Hashtable的全限定名表示為java/util/Hashtable鞍时。

簡單名稱
字段名和方法名以簡單名稱(非全限定名)形式出現(xiàn)在常量池入口。例如,一個指向類java.lang.Object所屬方法String toString()的常量池入口有一個形如"toString"的方法名逆巍。一個指向類java.lang.System所屬字段java.io.PrintStream out的常量池入口有一個形如“out”的字段名及塘。

描述符
字段的描述符給出了字段的類型;方法描述符給出了方法的返回值和方法參數(shù)的數(shù)量锐极、類型以及順序笙僚。

基本類型字符解釋表

字符 類型 含義
B byte 有符號字節(jié)型數(shù)
C char Unicode字符,UTF-16編碼
D double 雙精度浮點數(shù)
F float 單精度浮點數(shù)
I int 整數(shù)型
J long 長整數(shù)
S short 有符號短整數(shù)
Z boolean 布爾值 true/false
L Classname; reference 一個名為<Classname>的實例
[ reference 一個一維數(shù)組

字段描述符示例

描述符 字段聲明
I int i;
[[J long[][] windingRoad;
[Ljava/lang/Object; java.lang.Object[] stuff;
Ljava/util/Hashtable; java.util.Hashtable ht;
[[[Z boolean[][][] isReady;

方法描述符示例

描述符 方法聲明
( ) 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 regionMatchs(boolean ignoreCase, int toOffset, String other, int offset, int len);
([BII) I) int read (byte[] b, int off, int len);

2.3.3. 常量池的項目類型

常量池包括以下項目:

類型 標志 描述
CONSTANT_Utf8_info 1 UTF-8編碼的字符串
CONSTANT_Integer_info 3 整型字面量
CONSTANT_Float_info 4 浮點型字面量
CONSTANT_Long_info 5 長整型字面量
CONSTANT_Double_info 6 雙精度浮點型字面量
CONSTANT_Class_info 7 類或接口的符號引用
CONSTANT_String_info 8 字符串類型字面量
CONSTANT_Fieldref_info 9 字段的符號引用
CONSTANT_Methodref_info 10 類中方法的符號引用
CONSTANT_InterfaceMethodref_info 11 接口中方法的符號引用
CONSTANT_NameAndType_info 12 字段或方法的部分符號引用
CONSTANT_MethodHandle_info 15 表示方法句柄
CONSTANT_MethodType_info 16 標識方法類型
CONSTANT_InvokeDynamic_info 18 表示一個動態(tài)方法調用點

2.3.3.1. CONSTANT_Utf8_info

用于表示字符串常量的值灵再,結構如下:

CONSTANT_Utf8_info {
    u1 tag;// 值為1
    u2 length;// bytes[]數(shù)組的長度
    u1 bytes[length];
}

2.3.3.2. CONSTANT_Integer_info

CONSTANT_Integer_info {
    u1 tag;// 值為3
    u4 bytes;// 按照高位在前存儲的int值
}

2.3.3.3 CONSTANT_Float_info

CONSTANT_Float_info {
    u1 tag;// 值為4
    u2 bytes;// 按照高位在前存儲的float值
}

2.3.3.4. CONSTANT_Long_info

CONSTANT_Long_info {
    u1 tag;// 值為5
    u8 bytes;// 按照高位在前存儲的long值
}

2.3.3.5. CONSTANT_Double_info

CONSTANT_Double_info {
    u1 tag;// 值為6
    u8 bytes;// 按照高位在前存儲的double值
}

2.3.3.6. CONSTANT_Class_info

用于表示類或接口味咳,結構如下:

CONSTANT_Class_info {
    u1 tag;// 值為7
    u2 name_index;// 包含類或者接口全限定名的CONSTANT_Utf8_info表的索引
}

2.3.3.7. CONSTANT_String_info

用于表示java.lang.String類型的常量對象,結構如下:

CONSTANT_String_info {
    u1 tag;// 值為8
    u2 string_index;
}

2.3.3.8. CONSTANT_Fieldref_info

CONSTANT_Fieldref_info {
    u1 tag;// 值為9
    u2 class_index;
    u2 name_and_type_index;
}

2.3.3.9. CONSTANT_Methodref_info

CONSTANT_Methodref_info {
    u1 tag;// 值為10
    u2 class_index;
    u2 name_and_type_index;
}

2.3.3.10. CONSTANT_InterfaceMethodref_info

CONSTANT_InterfaceMethodref_info {
    u1 tag;// 值為11
    u2 class_index;
    u2 name_and_type_index;
}

2.3.3.11. CONSTANT_NameAndType_info

用于表示字段或方法檬嘀,結構如下:

CONSTANT_NameAndType_info {
    u1 tag;//值為12
    u2 name_index;
    u2 descriptor_index;
}

2.3.3.12. CONSTANT_MethodHandle_info

用于表示方法句柄,結構如下:

CONSTANT_MethodHandle_info {
    u1 tag;// 值為15
    u1 reference_kind;// 值必須在1至9之間(包括1和9)责嚷,它決定了方法句柄的類型鸳兽。方法句柄類型的值表示方法句柄的字節(jié)碼行為
    u2 reference_index;
}

2.3.3.13. CONSTANT_MethodType_info

用于表示方法類型,結構如下:

CONSTANT_MethodType_info {
    u1 tag;//值為16
    u2 descriptor_index;
}

2.3.3.14. CONSTANT_InvokeDynamic_info

用于表示invokedynamic指令所使用到的引導方法(Bootstrap Method)罕拂、引導方法使用到動態(tài)調用名稱(Dynamic Invocation Name)揍异、參數(shù)和請求返回類型、以及可以選擇性的附加被稱為靜態(tài)參數(shù)(Static Arguments)的常量序列爆班。

CONSTANT_InvokeDynamic_info {
    u1 tag;//值為18
    u2 bootstrap_method_attr_index;
    u2 name_and_type_index;
}

2.4. 訪問標志

在常量池結束之后衷掷,緊接著的兩個字節(jié)代表訪問標志(access_flags),這個標志用于識別一些類或者接口層次的訪問信息柿菩,包括:這個Class是類還是接口戚嗅;是否定義為public類型;是否定義為abstract類型枢舶;如果是類的話懦胞,是否被聲明為final等。

標志名稱 標志值 含義
ACC_PUBLIC 0x0001 是否為public類型
ACC_FINAL 0x0010 是否被聲明為final凉泄,只有類可設置
ACC_SUPER 0x0020 是否允許使用invokespecial字節(jié)碼指令的新語意躏尉,invokespecial指令的語意在JDK1.0.2發(fā)生過改變,為了區(qū)別這條指令使用哪種語意后众,JDK1.0.2之后編譯出來的類的這個標志都必須為真
ACC_INTERFACE 0x0200 標識這是一個接口
ACC_ABSTRACT 0x0400 是否為abstract類型胀糜,對于接口或者抽象類來說,此標志值為真蒂誉,其他類值為假
ACC_SYNTHETIC 0x1000 標識這個類并非由用戶代碼產(chǎn)生的
ACC_ANNOTATION 0x2000 標識這是一個注解
ACC_ENUM 0x4000 標識這是一個枚舉

2.5. 類索引教藻、父類索引與接口索引集合

類索引、父類索引與接口索引集合都順序排列在訪問標志之后拗盒。
類索引(this_class)和父類索引(super_class)都是一個u2類型的數(shù)據(jù)怖竭,而接口索引集合(interfaces)是一組u2類型的數(shù)據(jù)的集合,Class文件由這三項數(shù)據(jù)來確定這個類的繼承關系陡蝇。

2.6. 字段

字段表(field_info)用于描述接口或者類中聲明的變量痊臭。
字段(field)包括類級變量以及實例變量哮肚,但不包括方法內部聲明的局部變量。

field_info結構格式如下:

field_info {
    u2 access_flags;
    u2 name_index;// 簡單名稱索引
    u2 descriptor_index;//描述符索引
    u2 attribute_count;// 當前字段附加屬性的數(shù)量
    attribute_info attributes[attributes_count];
}

attributes項是由多個attribute_info表組成的列表广匙。attributes_count指出列表中attribute_info表的數(shù)量允趟。一個字段在其列表中可以有任意數(shù)量的屬性。由Java虛擬機規(guī)范定義的三種可能會出現(xiàn)在此項中的屬性是:ConstantValue鸦致、Deprecated和Synthetic潮剪。Java虛擬機唯一需要識別的屬性是ConstantValue屬性。虛擬機實現(xiàn)必須忽略任何無法識別的屬性分唾。

2.7. 方法

所有的方法(Method)抗碰,包括實例初始化方法和類初始化方法在內,都由method_info結構所定義绽乔。在一個Class文件中弧蝇,不會有兩個方法同時具有相同的方法名和描述符。

method_info結構格式如下:

method_info {
    u2 access_flags;
    u2 name_index;
    u2 descriptor_index;
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

有可能在class文件中出現(xiàn)的兩種編譯器產(chǎn)生的方法是:實例初始化方法(名為<init>)和類與接口初始化方法(名為<clinit>)折砸。

在此項中可能會出現(xiàn)的由Java虛擬機規(guī)范定義的四種屬性是:Code看疗、Deprecated、Exceptions和Synthetic睦授。Java虛擬機只需要識別Code和Exception屬性两芳。虛擬機實現(xiàn)必須忽略任何無法識別的屬性。

2.8. 屬性

屬性(Attributes)在Class文件格式中的ClassFile結構去枷、field_info結構怖辆、method_info結構和Code_attribute結構都有使用,所有屬性的通用格式如下:

attribute_info {
    u2 attribute_name_index;
    u4 attribute_length;
    u1 info[attribute_length];// 屬性數(shù)據(jù)
}

由規(guī)范定義的attribute_info表的類型:

名稱 使用者 描述
Code method_info 方法的字節(jié)碼和其他數(shù)據(jù)
ConstantValue field_info final變量的值
Deprecated field_info沉填、method_info 字段或者方法被禁用的指示符
Exceptions method_info 方法可能拋出的可被檢測的異常
InnerClasses ClassFile 內部疗隶、外部類的列表
LineNumberTable Code_attribute 方法的行號與字節(jié)碼的映射
LocalVariableTable Code_attribute 方法的局部變量的描述
SourceFile ClassFile 源文件名
Synthetic field_info、method_info 編譯器產(chǎn)生的字段或者方法的指示符

2.8.1. Code屬性

Code屬性是一個變長屬性翼闹,位于method_info結構的屬性表斑鼻。定義了方法的字節(jié)碼序列和其他信息。

一個Code屬性只為唯一一個方法猎荠、實例類初始化方法或類初始化方法保存Java虛擬機指令及相關輔助信息坚弱。所有Java虛擬機實現(xiàn)都必須能夠識別Code屬性。如果方法被聲明為native或者abstract類型关摇,那么對應的method_info結構不能有明確的Code屬性荒叶,其它情況下,method_info必須有明確的Code屬性输虱。

Code屬性的格式如下:

Code_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 max_stack;// 當前方法的操作數(shù)棧在運行執(zhí)行的任何時間點的最大深度
    u2 max_locals;// 分配在當前方法引用的局部變量表中的局部變量的個數(shù)些楣,包括調用此方法時用于傳遞參數(shù)的局部變量
    u4 code_length;
    u1 code[code_length];//當前方法的Java虛擬機字節(jié)碼
    u2 exception_table_length;
    {
        u2 start_pc;
        u2 end_pc;
        u2 handler_pc;
        u2 catch_type;
    } exception_table[exception_table_length];
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

2.8.2. ConstantValue屬性

ConstantValue屬性是定長屬性,位于field_info結構的屬性表中。ConstantValue屬性表示一個常量字段的值愁茁。在一個field_info結構的屬性表中最多只能有一個ConstantValue屬性蚕钦。

ConstantValue屬性的格式如下:

ConstantValue_attribute {
    u2 attribute_name_index;
    u4 attribute_length; 
    u2 constantvalue_index;
}

2.8.3. Deprecated屬性

Deprecated屬性是可選定長屬性。

Deprecated_attribute {
    u2 attribute_name_index;
    u4 attribute_length;//固定為0
}

2.8.4. Exceptions屬性

Exceptions屬性是一個變長屬性鹅很,它位于method_info結構的屬性表中嘶居。Exceptions屬性指出了一個方法需要檢查的可能拋出的異常。一個method_info結構中最多只能有一個Exceptions屬性促煮。

Exceptions屬性格式如下:

Exceptions_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 number_of_exceptions;
    u2 exception_index_table[number_of_exceptions];
}

2.8.5. InnerClasses屬性

InnerClasses屬性是一個變長屬性邮屁,位于ClassFile結構的屬性表。
InnerClasses屬性是在JDK1.1中為了支持內部類和內部接口而引入的菠齿。

InnerClasses_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 number_of_classes;
    {
        u2 inner_class_info_index;
        u2 outer_class_info_index;
        u2 inner_name_index;
        u2 inner_class_access_flags;
    }
} classes[number_of_classes];

2.8.6. LineNumberTable屬性

LineNumberTable屬性是可選變長屬性佑吝,位于Code結構的屬性表。它被調試器用于確定源文件中行號表示的內容在Java虛擬機的code[]數(shù)組中對應的部分绳匀。
LineNumberTable_attribute屬性格式如下:

LineNumberTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 line_number_table_length;
    {
        u2 start_pc;
        u2 line_number;
    } line_number_table[line_number_table_length];
}

2.8.7. LocalVariableTable屬性

LocalVariableTable是可選變長屬性迹蛤,位于Code屬性的屬性表中。它被調試器用于確定方法在執(zhí)行過程中局部變量的信息襟士。
LocalVariableTable屬性格式如下:

LocalVariableTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 local_variable_table_length;
    {
        u2 start_pc;
        u2 length;
        u2 name_index;
        u2 descriptor_index;
        u2 index;
    } local_variable_table[local_variable_table_length];
}

2.8.8. SourceFile屬性

SourceFile屬性是可選定長字段,位于ClassFile結構的屬性表嚷量。一個ClassFile結構中的屬性表最多只能包含一個SourceFile屬性陋桂。
SourceFile屬性格式如下:

 SourceFile_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 sourcefile_index;
}

2.8.8. Synthetic屬性

Synthetic屬性是定長屬性,位于ClassFile中的屬性表蝶溶。如果一個類成員沒有在源文件中出現(xiàn)嗜历,則必須標記帶有Synthetic屬性,或者設置ACC_SYNTHETIC標志抖所。
Synthetic_attribute屬性的格式如下:

Synthetic_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
}

參考:
《深入理解Java虛擬機_JVM高級特性與最佳實踐 第2版》
《深入Java虛擬機》
《Java虛擬機規(guī)范(Java SE 7)》

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末梨州,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子田轧,更是在濱河造成了極大的恐慌暴匠,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件傻粘,死亡現(xiàn)場離奇詭異每窖,居然都是意外死亡,警方通過查閱死者的電腦和手機弦悉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門窒典,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人稽莉,你說我怎么就攤上這事瀑志。” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵劈猪,是天一觀的道長昧甘。 經(jīng)常有香客問我,道長岸霹,這世上最難降的妖魔是什么疾层? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮贡避,結果婚禮上痛黎,老公的妹妹穿的比我還像新娘。我一直安慰自己刮吧,他們只是感情好湖饱,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著杀捻,像睡著了一般井厌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上致讥,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天仅仆,我揣著相機與錄音,去河邊找鬼垢袱。 笑死墓拜,一個胖子當著我的面吹牛,可吹牛的內容都是我干的请契。 我是一名探鬼主播咳榜,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼爽锥!你這毒婦竟也來了涌韩?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤氯夷,失蹤者是張志新(化名)和其女友劉穎臣樱,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腮考,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡擎淤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了秸仙。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嘴拢。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖寂纪,靈堂內的尸體忽然破棺而出席吴,到底是詐尸還是另有隱情赌结,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布孝冒,位于F島的核電站柬姚,受9級特大地震影響,放射性物質發(fā)生泄漏庄涡。R本人自食惡果不足惜量承,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望穴店。 院中可真熱鬧撕捍,春花似錦、人聲如沸泣洞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽球凰。三九已至狮腿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間呕诉,已是汗流浹背缘厢。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留甩挫,地道東北人昧绣。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像捶闸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子拖刃,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內容