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)》