一、class文件結(jié)構(gòu)
class文件用文本編輯器打開(kāi):
cafe babe 0000 0034 0014 0700 1207 0013
0100 1a44 4546 4155 4c54 5f41 4e49 4d41
5449 4f4e 5f44 5552 4154 494f 4e01 0001
4a01 000d 436f 6e73 7461 6e74 5661 6c75
6505 0000 0000 0000 01f4 0100 0e73 7461
7274 416e 696d 6174 696f 6e01 0004 284a
2956 0100 0f63 616e 6365 6c41 6e69 6d61
7469 6f6e 0100 0328 2956 0100 1269 7341
6e69 6d61 7469 6f6e 5374 6172 7465 6401
0003 2829 5a01 0019 7365 7443 6861 7274
416e 696d 6174 696f 6e4c 6973 7465 6e65
7201 003b 284c 6c65 6368 6f2f 6c69 622f
6865 6c6c 6f63 6861 7274 732f 616e 696d
6174 696f 6e2f 4368 6172 7441 6e69 6d61
7469 6f6e 4c69 7374 656e 6572 3b29 5601
000a 536f 7572 6365 4669 6c65 0100 1643
6861 7274 4461 7461 416e 696d 6174 6f72
2e6a 6176 6101 0031 6c65 6368 6f2f 6c69
622f 6865 6c6c 6f63 6861 7274 732f 616e
696d 6174 696f 6e2f 4368 6172 7444 6174
6141 6e69 6d61 746f 7201 0010 6a61 7661
2f6c 616e 672f 4f62 6a65 6374 0601 0001
0002 0000 0001 0019 0003 0004 0001 0005
0000 0002 0006 0004 0401 0008 0009 0000
0401 000a 000b 0000 0401 000c 000d 0000
0401 000e 000f 0000 0001 0010 0000 0002
0011
字節(jié)碼文件是由 十六進(jìn)制值組成 的,對(duì)于 JVM 來(lái)說(shuō),在讀取數(shù)據(jù)的時(shí)候,它會(huì) 以?xún)蓚€(gè)十六進(jìn)制值為一組,即 一個(gè)字節(jié) 進(jìn)行讀取。
根據(jù) JVM 規(guī)范的規(guī)定,Class 文件格式采用了一種類(lèi)似于 C 語(yǔ)言結(jié)構(gòu)體的偽結(jié)構(gòu)來(lái)存 儲(chǔ)數(shù)據(jù),而這種偽結(jié)構(gòu)中有且只有兩種數(shù)據(jù)類(lèi)型:無(wú)符號(hào)數(shù)和表。
1、無(wú)符號(hào)數(shù)
無(wú)符號(hào)數(shù)屬于基本的數(shù)據(jù)類(lèi)型,以 u1、u2、u4、u8 來(lái)分別代表 1 個(gè)字節(jié)、2 個(gè)字節(jié)、4 個(gè)字節(jié)和 8 個(gè)字節(jié)的無(wú)符號(hào)數(shù),無(wú)符號(hào)數(shù)可以用來(lái) 描述數(shù)字、索引引用、數(shù)量值或者按照UTF-8 碼構(gòu)成字符串值
2、表
u4:表示能夠保存4個(gè)字節(jié)的無(wú)符號(hào)整數(shù),u2同理。
ClassFile {
u4 magic; // 魔法數(shù)字,表明當(dāng)前文件是.class文件,固定0xCAFEBABE(咖啡寶貝)
u2 minor_version; // 分別為Class文件的副版本和主版本
u2 major_version;
u2 constant_pool_count; // 常量池計(jì)數(shù)
cp_info constant_pool[constant_pool_count-1]; // 常量池內(nèi)容
u2 access_flags; // 類(lèi)訪(fǎng)問(wèn)標(biāo)識(shí)
u2 this_class; // 當(dāng)前類(lèi)
u2 super_class; // 父類(lèi)
u2 interfaces_count; // 實(shí)現(xiàn)的接口數(shù)
u2 interfaces[interfaces_count]; // 實(shí)現(xiàn)接口信息
u2 fields_count; // 字段數(shù)量
field_info fields[fields_count]; // 包含的字段信息
u2 methods_count; // 方法數(shù)量
method_info methods[methods_count]; // 包含的方法信息
u2 attributes_count; // 屬性數(shù)量
attribute_info attributes[attributes_count]; // 各種屬性
}
- magic:每個(gè) Class 文件的頭 4 個(gè)字節(jié)被稱(chēng)為魔數(shù)(Magic Number),它的唯一作用是確定這個(gè)文件是否為一個(gè)能被虛擬機(jī)所接受的 Class 文件。很多文件存儲(chǔ)標(biāo)準(zhǔn)中都使用魔數(shù)來(lái)進(jìn)行身份識(shí)別, 譬如圖片格式,如 gif 或者 jpeg 等在文件頭中都存有魔數(shù)。使用魔數(shù)而不是擴(kuò)展名來(lái)進(jìn)行識(shí)別主要是基于安全方面的考慮,因?yàn)槲募U(kuò)展名可以隨意地改動(dòng)。并且,Class 文件的魔數(shù)獲得很有 “浪漫氣息”,值為:0xCAFEBABE(咖啡寶貝)。
- minor_version:2 個(gè)字節(jié)長(zhǎng),表示當(dāng)前 Class 文件的次版號(hào)。
- major_version:2 個(gè)字節(jié)長(zhǎng),表示當(dāng)前 Class 文件的主版本號(hào)。(Java 的版本號(hào)是從 45 開(kāi)始 的,JDK 1.1 之后的每個(gè) JDK 大版本發(fā)布會(huì)在主版本號(hào)向上加 1(JDK 1.0~1.1 使用了 45.0~45.3 的版本號(hào)),例如 JDK 1.8 就是 52.0)。需要注意的是,虛擬機(jī)會(huì)拒絕執(zhí)行超過(guò)其版本號(hào)的 Class 文件。
- constant_pool_count:常量池?cái)?shù)組元素個(gè)數(shù)。
- constant_pool:常量池,是一個(gè)存儲(chǔ)了 cp_info 信息的數(shù)組,每一個(gè) Class 文件都有一個(gè)與之對(duì)應(yīng)的常量池。(注意:cp_info 數(shù)組的索引從 1 開(kāi)始)
- access_flags:表示當(dāng)前類(lèi)的訪(fǎng)問(wèn)權(quán)限,例如:public、private。
- this_class 和 super_class:存儲(chǔ)了指向常量池?cái)?shù)組元素的索引,this_class 中索引指向的內(nèi)容為當(dāng)前類(lèi)名,而 super_class 中索引則指向其父類(lèi)類(lèi)名。
- interfaces_count 和 interfaces:同上,它們存儲(chǔ)的也只是指向常量池?cái)?shù)組元素的索引。其內(nèi)容分別表示當(dāng)前類(lèi)實(shí)現(xiàn)了多少個(gè)接口和對(duì)應(yīng)的接口類(lèi)類(lèi)名。
- fields_count 和 fields:表示成員變量的數(shù)量和其信息,信息由 field_info 結(jié)構(gòu)體表示。
- methods_count 和 methods:表示成員函數(shù)的數(shù)量和它們的信息,信息由 method_info 結(jié)構(gòu)體表示。
- attributes_count 和 attributes:表示當(dāng)前類(lèi)的屬性信息,每一個(gè)屬性都有一個(gè)與之對(duì)應(yīng)的 attribute_info 結(jié)構(gòu)。常見(jiàn)的屬性信息如調(diào)試信息,它需要記錄某句代碼對(duì)應(yīng)源代碼的哪一行,此外,如函數(shù)對(duì)應(yīng)的 JVM 字節(jié)碼、注解信息也是屬性信息。
二、常量池
常量池中主要存放兩大類(lèi)常量:字面量(Literal)和符號(hào)引用(Symbolic References)
常量項(xiàng) Utf8
常量項(xiàng) Utf8 的數(shù)據(jù)結(jié)構(gòu)如下所示:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
- tag:值為 1,表示是 CONSTANT_Utf8_info 類(lèi)型表。
- length:length 表示 bytes 的長(zhǎng)度,比如 length = 10,則表示接下來(lái)的數(shù)據(jù)是 10 個(gè)連續(xù)的 u1 類(lèi)型數(shù)據(jù)。
- bytes:u1 類(lèi)型數(shù)組,保存有真正的常量數(shù)據(jù)。
常量項(xiàng) Class、Filed、Method、Interface、String
CONSATNT_Class_info {
u1 tag;
u2 name_index;
}
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_MethodType_info {
u1 tag;
u2 descriptor_index;
}
CONSTANT_InterfaceMethodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
CONSATNT_NameAndType_info {
u1 tag;
u2 name_index;
u2 descriptor_index
}
name_index:指向常量池中索引為 name_index 的常量表。比如 name_index = 6,表明它指向常量池中第 6 個(gè)常量。
class_index:指向當(dāng)前方法、字段等的所屬類(lèi)的引用。
name_and_type_index:指向當(dāng)前方法、字段等的名字和類(lèi)型的引用。
name_index:指向某字段或方法等的名稱(chēng)字符串的引用。
descriptor_index:指向某字段或方法等的類(lèi)型字符串的引用。
注意:CONSTANT_String 和 CONSTANT_Utf8 的區(qū)別
CONSTANT_Utf8:真正存儲(chǔ)了字符串的內(nèi)容,其對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)中有一個(gè)字節(jié)數(shù)組,字符串便醞釀其中。
CONSTANT_String:本身不包含字符串的內(nèi)容,但其具有一個(gè)指向 CONSTANT_Utf8 常量項(xiàng)的索引。
常量項(xiàng) Integer、Long、Float、Double
CONSATNT_Integer_info {
u1 tag;
u4 bytes;
}
CONSTANT_Long_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Float_info {
u1 tag;
u4 bytes;
}
CONSTANT_Float_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
三、信息描述規(guī)則
1、數(shù)據(jù)類(lèi)型
原始數(shù)據(jù)類(lèi)型:
Java 類(lèi)型的 byte、char、double、float、int、long、short、boolean => "B"、"C"、"D"、"F"、"I"、"J"、"S"、"Z"。引用數(shù)據(jù)類(lèi)型:
ClassName => L + 全路徑類(lèi)名(其中的 "." 替換為 "/",最后加分號(hào)),例如 String => Ljava/lang/String。數(shù)組(引用類(lèi)型):
不同類(lèi)型的數(shù)組 => "[該類(lèi)型對(duì)應(yīng)的描述名",例如 int 數(shù)組 => "[I",String 數(shù)組 => "[Ljava/lang/Sting",二維 int 數(shù)組 => "[[I"。
2、成員變量
在 JVM 規(guī)范之中,成員變量即 Field Descriptor 的描述規(guī)則如下所示:
FiledDescriptor:
# 1、僅包含 FieldType 一種信息
FieldType
FiledType:
# 2、FiledType 的可選類(lèi)型
BaseType | ObjectType | ArrayType
BaseType:
B | C | D | F | I | J | S | Z
ObjectType:
L + 全路徑ClassName;
ArrayType:
[ComponentType:
# 3、與 FiledType 的可選類(lèi)型一樣
ComponentType:
3、成員函數(shù)描述規(guī)則
在 JVM 規(guī)范之中,成員函數(shù)即 Method Descriptor 的描述規(guī)則如下所示:
MethodDescriptor:
# 1、括號(hào)內(nèi)的是參數(shù)的數(shù)據(jù)類(lèi)型描述,* 表示有 0 至多個(gè) ParameterDescriptor,最后是返回值類(lèi)型描述
( ParameterDescriptor* ) ReturnDescriptor
ParameterDescriptor:
FieldType
ReturnDescriptor:
FieldType | VoidDescriptor
VoidDescriptor:
// 2、void 的描述規(guī)則為 "V"
V
四、filed_info 與 method_info
field_info {
u2 access_flags;
u2 name
u2 descriptor_index
u2 attributes_count
attribute_info attributes[attributes_count]
}
method_info {
u2 access_flags;
u2 name
u2 descriptor_index
u2 attributes_count
attribute_info attributes[attributes_count]
}
可以看到,filed_info 與 method_info 都包含有 訪(fǎng)問(wèn)標(biāo)志、名字引用、描述信息、屬性數(shù)量與存儲(chǔ)屬性 的數(shù)據(jù)結(jié)構(gòu)。對(duì)于 method_info 所描述的成員函數(shù)來(lái)說(shuō),它的內(nèi)容經(jīng)過(guò)編譯之后得到的 Java 字節(jié)碼會(huì)保存在屬性之中。
注意:類(lèi)構(gòu)造器為 “< clinit >” 方法,而實(shí)例構(gòu)造器為 “< init >” 方法。
五、access_flags
1、Class 的 access_flags 取值類(lèi)型
| 標(biāo)志名 | 標(biāo)志值 | 標(biāo)志含義 |
|---|---|---|
| ACC_PUBLIC | 0x0001 | public類(lèi)型 |
| ACC_FINAL | 0x0010 | final類(lèi)型 |
| ACC_SUPER | 0x0020 | 使用新的invokespecial語(yǔ)義 |
| ACC_INTERFACE | 0x0200 | 接口類(lèi)型 |
| ACC_ABSTRACT | 0x0400 | 抽象類(lèi)型 |
| ACC_SYNTHETIC | 0x1000 | 該類(lèi)不由用戶(hù)代碼生成 |
| ACC_ANNOTATION | 0x2000 | 注解類(lèi)型 |
| ACC_ENUM | 0x4000 | 枚舉類(lèi)型 |
2、Filed 的 access_flag 取值類(lèi)型
| 標(biāo)志名 | 標(biāo)志值 | 標(biāo)志含義 |
|---|---|---|
| ACC_PUBLIC | 0x0001 | public |
| ACC_PRIVATE | 0x0002 | private |
| ACC_PROTECTED | 0x0004 | protected |
| ACC_STATIC | 0x0008 | static |
| ACC_FINAL | 0x0010 | final |
| ACC_VOLATILE | 0x0040 | volatile |
| ACC_TRANSIENT | 0x0080 | transient,不能被序列化 |
| ACC_SYNTHETIC | 0x1000 | 由編譯器自動(dòng)生成 |
| ACC_ENUM | 0x4000 | enum,字段為枚舉類(lèi)型 |
3、Method 的 access_flag 取值
| 標(biāo)志名 | 標(biāo)志值 | 標(biāo)志含義 |
|---|---|---|
| ACC_PUBLIC | 0x0001 | public |
| ACC_PRIVATE | 0x0002 | private |
| ACC_PROTECTED | 0x0004 | protected |
| ACC_STATIC | 0x0008 | static |
| ACC_FINAL | 0x0010 | final |
| ACC_SYNCHRONIZED | 0x0020 | synchronized |
| ACC_BRIDGE | 0x0040 | bridge,方法由編譯器產(chǎn)生 |
| ACC_VARARGS | 0x0080 | 該方法帶有變長(zhǎng)參數(shù) |
| ACC_NATIVE | 0x0100 | native |
| ACC_ABSTRACT | 0x0400 | abstract |
| ACC_STRICT | 0x0800 | strictfp |
| AACC_SYNTHETIC | 0x1000 | 方法由編譯器生成 |
六、屬性
attribute_info 的數(shù)據(jù)結(jié)構(gòu)偽代碼如下所示:
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
- attribute_name_index:為 CONSTANT_Utf8 類(lèi)型常量項(xiàng)的索引,表示屬性的名稱(chēng)。
- attribute_length:屬性的長(zhǎng)度。
- info:屬性具體的內(nèi)容。
1、attribute_name_index
- ConstantValue:僅出現(xiàn)在 filed_info 中,描述常量成員域的值,通知虛擬機(jī)自動(dòng)為靜態(tài)變量賦值。對(duì)于非 static 類(lèi)型的變量(也就是實(shí)例變量)的賦值是在實(shí)例構(gòu)造器方法中進(jìn)行的;而對(duì) 于類(lèi)變量,則有兩種方式可以選擇:在類(lèi)構(gòu)造器方法中或者使用 ConstantValue 屬性。如果變量沒(méi)有被 final 修飾,或者并非基本類(lèi)型及字 符串,則將會(huì)選擇在方法中進(jìn)行初始化。
- Code:僅出現(xiàn) method_info 中,描述函數(shù)內(nèi)容,即該函數(shù)內(nèi)容編譯后得到的虛擬機(jī)指令,try/catch 語(yǔ)句對(duì)應(yīng)的異常處理表等等。
- StackMapTable:在 JDK 1.6 發(fā)布后增加到了 Class 文件規(guī)范中,它是一個(gè)復(fù)雜的變長(zhǎng)屬性。這個(gè)屬性會(huì)在虛擬機(jī)類(lèi)加載的字節(jié)碼驗(yàn)證階段被新類(lèi)型檢查驗(yàn)證器(Type Checker)使用,目的在于代替以前比較消耗性能的基于數(shù)據(jù)流 分析的類(lèi)型推導(dǎo)驗(yàn)證器。它省略了在運(yùn)行期通過(guò)數(shù)據(jù)流分析去確認(rèn)字節(jié)碼的行為邏輯合法性的步驟,而是在編譯階 段將一系列的驗(yàn)證類(lèi)型(Verification Types)直接記錄在 Class 文件之中,通過(guò)檢查這些驗(yàn)證類(lèi)型代替了類(lèi)型推導(dǎo)過(guò)程,從而大幅提升了字節(jié)碼驗(yàn)證的性能。這個(gè)驗(yàn)證器在 JDK 1.6 中首次提供,并在 JDK 1.7 中強(qiáng)制代替原本基于類(lèi)型推斷的字節(jié)碼驗(yàn)證器。StackMapTable 屬性中包含零至多個(gè)棧映射幀(Stack Map Frames),其中的類(lèi)型檢查驗(yàn)證器會(huì)通過(guò)檢查目標(biāo)方法的局部變量和操作數(shù)棧所需要的類(lèi)型來(lái)確定一段字節(jié)碼指令是否符合邏輯約束。
- Exceptions:當(dāng)函數(shù)拋出異?;蝈e(cuò)誤時(shí),method_info 將會(huì)保存此屬性。
- InnerClasses:用于記錄內(nèi)部類(lèi)與宿主類(lèi)之間的關(guān)聯(lián)。
- EnclosingMethod
- Synthetic:標(biāo)識(shí)方法或字段為編譯器自動(dòng)生成的。
- Signature:JDK 1.5 中新增的屬性,用于支持泛型情況下的方法簽名,由于 Java 的泛型采用擦除法實(shí)現(xiàn),在為了避免類(lèi)型信息被擦除后導(dǎo)致簽名混亂,需要這個(gè)屬性記錄泛型中的相關(guān)信息。
- SourceFile:包含一個(gè)指向 Utf8 常量項(xiàng)的索引,即 Class 對(duì)應(yīng)的源碼文件名。
- SourceDebugExtension:用于存儲(chǔ)額外的調(diào)試信息。
- LineNumberTable:Java 源碼的行號(hào)與字節(jié)碼指令的對(duì)應(yīng)關(guān)系。
- LocalVariableTable:局部變量數(shù)組/本地變量表,用于保存變量名,變量定義所在行。
- LocalVariableTypeTable:JDK 1.5 中新增的屬性,它使用特征簽名代替描述符,是為了引入泛型語(yǔ)法之后能描述泛型參數(shù)化類(lèi)型而添加。
- Deprecated
- RuntimeVisibleAnnotations
- RuntimeInvisibleAnnotations
- RuntimeVisibleParameterAnnotations
- RuntimeInvisibleParameterAnnotations
- AnnotationDefault
- BootstrapMethods:JDK 1.7中新增的屬性,用于保存 invokedynamic 指令引用的引導(dǎo)方法限定符。切記,類(lèi)文件的屬性表中最多也只能有一個(gè) BootstrapMethods 屬性。
**LineNumberTable **
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];
}
1、start_pc:為 code[] 數(shù)組元素的索引,用于指向 Code_attribute 中 code 數(shù)組某處指令。
2、line_number:為 start_pc 對(duì)應(yīng)源文件代碼的行號(hào)。需要注意的是,多個(gè) line_number_table 元素可以指向同一行代碼,因?yàn)橐恍?Java 代碼很可能被編譯成多條指令。
**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];
}
其中最重要的元素是 local_variable_table 數(shù)組,其中的 start_pc 與 length 這兩個(gè)參數(shù)
決定了一個(gè)局部變量在 code 數(shù)組中的有效范圍。
需要注意的是,每個(gè)非 static 函數(shù)都會(huì)自動(dòng)創(chuàng)建一個(gè)叫做 this 的本地變量,代表當(dāng)前是在哪個(gè)對(duì)象上調(diào)用此函數(shù)。并且,this 對(duì)象是位于局部變量數(shù)組第1個(gè)位置(即 Slot = 0),它的作用范圍是貫穿整個(gè)函數(shù)的。
此外,在 JDK 1.5 引入泛型之后,LocalVariableTable 屬性增加了一個(gè) “姐妹屬性”: LocalVariableTypeTable,這個(gè)新增的屬性結(jié)構(gòu)與 LocalVariableTable 非常相似,僅僅是把記錄 的字段描述符的 descriptor_index 替換成了字段的特征簽名(Signature),對(duì)于非泛型類(lèi)型來(lái) 說(shuō),描述符和特征簽名能描述的信息是基本一致的,但是泛型引入之后,由于描述符中泛型的參數(shù)化類(lèi)型被擦除掉,描述符就不能準(zhǔn)確地描述泛型類(lèi)型了,因此出現(xiàn)了 LocalVariableTypeTable。
2、Code_attribute
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
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];
}
- attribute_name_index、attribute_length:attribute_length 的值為整個(gè) Code 屬性減去 attribute_name_index 和 attribute_length 的長(zhǎng)度。
- max_stack:為當(dāng)前方法執(zhí)行時(shí)的最大棧深度,所以 JVM 在執(zhí)行方法時(shí),線(xiàn)程棧的棧幀(操作數(shù)棧,operand satck)大小是可以提前知道的。每一個(gè)函數(shù)執(zhí)行的時(shí)候都會(huì)分配一個(gè)操作數(shù)棧和局部變量數(shù)組,而 Code_attribure 需要包含它們,以便 JVM 在執(zhí)行函數(shù)前就可以分配相應(yīng)的空間。
- max_locals:為當(dāng)前方法分配的局部變量個(gè)數(shù),包括調(diào)用方式時(shí)傳遞的參數(shù)。long 和 double 類(lèi)型計(jì)數(shù)為 2,其他為 1。max_locals 的單位是 Slot,Slot 是
虛擬機(jī)為局部變量分配內(nèi)存所使用的最小單位。局部變量表中的 Slot 可以重用,當(dāng)代碼執(zhí)行超出一個(gè)局部變量的作用域時(shí),這個(gè)局部變量 所占的 Slot 可以被其他局部變量所使用,Javac 編譯器會(huì)根據(jù)變量的作用域來(lái)分配 Slot 給各個(gè) 變量使用,然后計(jì)算出 max_locals 的大小。 - code_length:為方法編譯后的字節(jié)碼的長(zhǎng)度。
- code:用于存儲(chǔ)字節(jié)碼指令的一系列字節(jié)流。既然叫字節(jié)碼指令,那么每個(gè)指令就是一個(gè) u1 類(lèi)型的單字節(jié)。一個(gè) u1 數(shù)據(jù)類(lèi)型的取值范圍為 0x00~0xFF,對(duì)應(yīng)十進(jìn)制的 0~255,也就是一共可以表達(dá) 256 條指令。
- exception_table_length:表示 exception_table 的長(zhǎng)度。
- exception_table:每個(gè)成員為一個(gè) ExceptionHandler,并且一個(gè)函數(shù)可以包含多個(gè) try/catch 語(yǔ)句,一個(gè) try/catch 語(yǔ)句對(duì)應(yīng) exception_table 數(shù)組中的一項(xiàng)。
- start_pc、end_pc:為異常處理字節(jié)碼在 code[] 的索引值。當(dāng)程序計(jì)數(shù)器在 [start_pc, end_pc) 內(nèi)時(shí),表示異常會(huì)被該 ExceptionHandler 捕獲。
- handler_pc:表示 ExceptionHandler 的起點(diǎn),為 code[] 的索引值。
- catch_type:為 CONSTANT_Class 類(lèi)型常量項(xiàng)的索引,表示處理的異常類(lèi)型。如果該值為 0,則該 ExceptionHandler 會(huì)在所有異常拋出時(shí)會(huì)被執(zhí)行,可以用來(lái)實(shí)現(xiàn) finally 代碼。當(dāng) catch_type 的值為 0 時(shí),代表任意異常情況都需要轉(zhuǎn)向到 handler_pc 處進(jìn)行處理。此外,編譯器使用異常表而不是簡(jiǎn)單的跳轉(zhuǎn)命令來(lái)實(shí)現(xiàn) Java 異常及 finally 處理機(jī)制。
- attributes_count 和 attributes:表示該 exception_table 擁有的 attribute 數(shù)量與數(shù)據(jù)。