1 解析示例
示例源碼
public class ClassStructureMethod {
public void greeting() throws Exception {
try {
int a=1;
int b=1;
int c=a+b;
System.out.println(c);
}catch (Exception e){
System.out.println("catch");
}finally {
System.out.println("finally");
}
}
}
示例常量池
Constant pool:
#1 = Methodref #9.#30 // java/lang/Object."<init>":()V
#2 = Fieldref #31.#32 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Methodref #33.#34 // java/io/PrintStream.println:(I)V
#4 = String #35 // finally
#5 = Methodref #33.#36 // java/io/PrintStream.println:(Ljava/lang/String;)V
#6 = Class #37 // java/lang/Exception
#7 = String #38 // catch
#8 = Class #39 // jvm/ClassStructureMethod
#9 = Class #40 // java/lang/Object
#10 = Utf8 <init>
#11 = Utf8 ()V
#12 = Utf8 Code
#13 = Utf8 LineNumberTable
#14 = Utf8 LocalVariableTable
#15 = Utf8 this
#16 = Utf8 Ljvm/ClassStructureMethod;
#17 = Utf8 greeting
#18 = Utf8 a
#19 = Utf8 I
#20 = Utf8 b
#21 = Utf8 c
#22 = Utf8 e
#23 = Utf8 Ljava/lang/Exception;
#24 = Utf8 StackMapTable
#25 = Class #37 // java/lang/Exception
#26 = Class #41 // java/lang/Throwable
#27 = Utf8 Exceptions
#28 = Utf8 SourceFile
#29 = Utf8 ClassStructureMethod.java
#30 = NameAndType #10:#11 // "<init>":()V
#31 = Class #42 // java/lang/System
#32 = NameAndType #43:#44 // out:Ljava/io/PrintStream;
#33 = Class #45 // java/io/PrintStream
#34 = NameAndType #46:#47 // println:(I)V
#35 = Utf8 finally
#36 = NameAndType #46:#48 // println:(Ljava/lang/String;)V
#37 = Utf8 java/lang/Exception
#38 = Utf8 catch
#39 = Utf8 jvm/ClassStructureMethod
#40 = Utf8 java/lang/Object
#41 = Utf8 java/lang/Throwable
#42 = Utf8 java/lang/System
#43 = Utf8 out
#44 = Utf8 Ljava/io/PrintStream;
#45 = Utf8 java/io/PrintStream
#46 = Utf8 println
#47 = Utf8 (I)V
#48 = Utf8 (Ljava/lang/String;)V
2 方法表前置結(jié)構(gòu)
類訪問標(biāo)志2個字節(jié)(u2)來描述阱当,對應(yīng)16進制0x0021俏扩,對照J(rèn)ava虛擬機規(guī)范定義,匹配ACC_PUBLIC弊添、ACC_SUPER录淡,表示當(dāng)前類的修飾符為public。
類名用2位字節(jié)(u2)來描述,對應(yīng)16進制0x0008油坝,即十進制的8嫉戚,8是常量池數(shù)組的一個下標(biāo),指向常量池中一個常量澈圈,通過對照javap中結(jié)果中對應(yīng)到一個CONSTANT_Class_info類型的常量(下標(biāo)#8),CONSTANT_Class_info類型常量其值轉(zhuǎn)換為整數(shù)20彬檀,指向常量池中一個常量,通過對照javap中結(jié)果中對應(yīng)到一個CONSTANT_Utf8_info類型的常量(下標(biāo)#39)瞬女,字符串值為"jvm/ClassStructureMethod"窍帝。
父類名用2位字節(jié)(u2)來描述,對應(yīng)16進制0x0009,即十進制的9诽偷,9是常量池數(shù)組的一個下標(biāo)坤学,指向常量池中一個常量,通過對照javap中結(jié)果中對應(yīng)到一個CONSTANT_Class_info類型的常量(下標(biāo)#9),CONSTANT_Class_info類型常量其值轉(zhuǎn)換為整數(shù)21报慕,指向常量池中一個常量拥峦,通過對照javap中結(jié)果中對應(yīng)到一個CONSTANT_Utf8_info類型的常量(下標(biāo)#40),字符串值為"java/lang/Object"卖子。
類接口數(shù)量用2位字節(jié)(u2)來描述,對應(yīng)16進制0x0000,即十進制的0刑峡,表示當(dāng)前類沒有實現(xiàn)接口洋闽。因此Class文件中不存在接口名稱描述。
字段數(shù)量用2位字節(jié)(u2)來描述,對應(yīng)16進制0x0000突梦,即十進制的0诫舅,表示當(dāng)前類沒有字段。因此Class文件中不存在字段的描述宫患。
2 方法表結(jié)構(gòu)
方法表集合的結(jié)構(gòu)
方法表集合的結(jié)構(gòu)被劃分為方法表數(shù)量和方法表集合刊懈。
方法表數(shù)量(methods_count):表示類中定義的方法個數(shù),其中除了自定義的方法外娃闲,每一個類中都會存在名稱為"<init>"構(gòu)造函數(shù)虚汛,如果類中定義靜態(tài)變量或者靜態(tài)塊,則還會存在一個名稱為"<clinit>"類初始化方法皇帮。
方法表(method_info):表示類中定義某一個方法卷哩。其中涵蓋了方法的所有信息。
3 方法表數(shù)量(methods_count)
Java虛擬機規(guī)范中方法表數(shù)量用2個字節(jié)(u2)用來表示属拾。
示例中方法表數(shù)量
示例中方法數(shù)量将谊,對應(yīng)16進制0x0002冷溶,即十進制的2,代表Class文件中有2個方法尊浓。
對比源代碼中ClassStructureMethod類定義逞频,存在一個構(gòu)造方法<init>和自定義方法greeting(),共兩個方法栋齿。
public class ClassStructureMethod {
public void greeting() throws Exception {
try {
int a=1;
int b=1;
int c=a+b;
System.out.println(c);
}catch (Exception e){
System.out.println("catch");
}finally {
System.out.println("finally");
}
}
}
Class文件中init方法的描述
本章節(jié)主要用來解析greeting方法在Class文件中的結(jié)構(gòu)苗胀,在此跳過<init>方法部分描述。
Class文件中init方法的描述
4 方法表(methods_info)
Java虛擬機規(guī)范定義方法表結(jié)構(gòu)
- 方法訪問標(biāo)志(access_flags)
- 方法名稱索引(name_index)
- 方法描述符索引(descriptor_index)
- 方法屬性表集合(attributes)
4.1 方法訪問標(biāo)志(access_flags)
Java虛擬機規(guī)范中方法訪問標(biāo)志用2個字節(jié)(u2)用來表示褒颈。
Java虛擬機規(guī)范定義方法訪問標(biāo)志
示例中方法訪問標(biāo)志
字段修飾符用2個字節(jié)(u2)來描述柒巫,對應(yīng)16進制0x0001,對照J(rèn)VM規(guī)范表中方法方法訪問標(biāo)志為ACC_PUBLIC,表示方法被"public"修飾
對比源代碼中可以發(fā)現(xiàn)greeting方法的修飾符為"public"相匹配
public class ClassStructureMethod {
public void greeting() throws Exception {
try {
int a=1;
int b=1;
int c=a+b;
System.out.println(c);
}catch (Exception e){
System.out.println("catch");
}finally {
System.out.println("finally");
}
}
}
4.2 方法名稱(name_index)
Java虛擬機規(guī)范中方法名稱用2個字節(jié)(u2)用來表示谷丸”ぬ停可以換算成為一個整數(shù),這個整數(shù)是常量池數(shù)組的一個下標(biāo)刨疼,指向中一個CONSTANT_Utf8_info類型的常量用來描述方法的名稱泉唁。
示例方法名稱
方法名用2位字節(jié)(u2)來描述,對應(yīng)16進制0x0011,即十進制的17揩慕,17是常量池數(shù)組的一個下標(biāo)亭畜,指向常量池中一個常量,通過對照javap中結(jié)果中對應(yīng)到一個CONSTANT_Utf8_info類型的常量(下標(biāo)#17)迎卤,對應(yīng)字符串"greeting",表示方法名稱
4.3 方法描述符(descriptor_index)
按照J(rèn)ava虛擬機規(guī)范方法描述符用2位字節(jié)(u2)來描述拴鸵,可以換算成為一個整數(shù),這個整數(shù)是常量池數(shù)組的一個下標(biāo)蜗搔,指向中一個CONSTANT_Utf8_info類型的常量用來描述方法描述符劲藐。
關(guān)于方法的描述符在常量池中講過主要用來描述方法的參數(shù)和返回類型。
示例中方法描述符
方法修飾符用2個字節(jié)(u2)描述,對應(yīng)16進制0x000B樟凄,即十進制的11聘芜,11是常量池數(shù)組的一個下標(biāo),指向常量池中一個常量缝龄,通過對照javap中結(jié)果中對應(yīng)到一個CONSTANT_Utf8_info類型的常量(下標(biāo)#11)汰现,對應(yīng)字符串"()V",表示greeting方法不需要傳遞參數(shù),且不需要返回值
4.4 方法中的屬性
4.4.1 屬性表
屬性表(attribute_info)作用于Class文件叔壤、字段表瞎饲、方法表。它們都可以攜帶自己的屬性集合炼绘,用于描述某些場景專有的信息企软。
4.4.2 虛擬機規(guī)范中定義屬性表類型
4.4.3 屬性表集合的結(jié)構(gòu)
屬性表集合的結(jié)構(gòu)被劃分為屬性表數(shù)量和屬性表集合。
屬性表數(shù)量(methods_count):表示方法中定義的屬性個數(shù)饭望。
屬性表(method_info):表示方法中定義某一個屬性仗哨。其中涵蓋了屬性的所有信息形庭。
4.4.4 用于方法中屬性表
對于方法來說常用到的屬性有如下幾種:"code","Exception","Deprecated","Synthetic"。
code:用來表示方法中java字節(jié)碼
Exception:用來記錄方法中的異常信息厌漂。
Deprecated:用來表示方法是否被@Deprecated修飾
Synthetic:表示方法是否被編譯器自動生成萨醒。
4.4.5 屬性表通用格式
屬性名稱索引:屬性名稱索引占用2個字節(jié),可以換算成為一個整數(shù)苇倡,這個整數(shù)是常量池數(shù)組的一個下標(biāo)富纸,指向中一個CONSTANT_Utf8_info類型的常量用來描述屬性名稱。通過屬性名稱就可以確定屬性表類型
屬性長度:占用4個字節(jié)旨椒,它的值表示緊跟其后的多少個字節(jié)是拿來表示這個屬性信息的晓褪。
屬性值:由若個個字節(jié)構(gòu)造,字節(jié)的大小取決屬性的長度
4.5 屬性表數(shù)量
Java虛擬機規(guī)范中屬性表數(shù)量用2個字節(jié)(u2)用來表示综慎。
示例中屬性表數(shù)量
示例中屬性表涣仿,對應(yīng)16進制0x0002,即十進制的2示惊,代表方法中有2個屬性好港。
4.6 屬性表
4.6.1 Code屬性
4.6.1.1 Code屬性名稱索引
屬性名稱索引用2個字節(jié)(u2)描述,對應(yīng)16進制0x000C,即十進制的12米罚,12是常量池數(shù)組的一個下標(biāo)钧汹,指向常量池中一個常量,通過對照javap中結(jié)果中對應(yīng)到一個CONSTANT_Utf8_info類型的常量(下標(biāo)#12)录择,對應(yīng)字符串"code",表示當(dāng)前屬性code類型的屬性拔莱。
4.6.1.2 Code屬性結(jié)構(gòu)
通過屬性名稱索引知道了方法的第一個索引名稱為"code".其虛擬機規(guī)范中的定義如下:
- attribute_name_index,屬性名稱索引,占有2個字節(jié)隘竭,其內(nèi)的值指向了常量池中的某一項辨宠,該項表示字符串“Code”;
- attribute_length,屬性長度,占有 4個字節(jié)货裹,其內(nèi)的值表示后面有多少個字節(jié)是屬于此Code屬性表的;
- max_stack,操作數(shù)棧深度的最大值精偿,占有 2 個字節(jié)弧圆,在方法執(zhí)行的任意時刻,操作數(shù)棧都不應(yīng)該超過這個值笔咽,虛擬機的運行的時候搔预,會根據(jù)這個值來設(shè)置該方法對應(yīng)的棧幀(Stack Frame)中的操作數(shù)棧的深度;
- max_locals,最大局部變量數(shù)目叶组,占有 2個字節(jié)拯田,其內(nèi)的值表示局部變量表所需要的存儲空間大小甩十;
- code_length,Java字節(jié)碼的長度船庇,占有 4 個字節(jié)吭产,表示跟在其后的多少個字節(jié)表示的是機器指令;
- code,Java字節(jié)碼鸭轮,該區(qū)域占有的字節(jié)數(shù)目由 code_length中的值決定臣淤。JVM最底層的要執(zhí)行的Java字節(jié)碼指令就存儲在這里;
- exception_table_length,顯式異常表長度窃爷,占有2個字節(jié)邑蒋,如果在方法代碼中出現(xiàn)了try{} catch()形式的結(jié)構(gòu),該值不會為空按厘,緊跟其后會跟著若干個exception_table結(jié)構(gòu)體医吊,以表示異常捕獲情況;
- exception_table逮京,顯式異常表卿堂,占有8 個字節(jié),start_pc,end_pc,handler_pc中的值都表示的是PC計數(shù)器中的指令地址造虏。exception_table表示的意思是:如果字節(jié)碼從第start_pc行到第end_pc行之間出現(xiàn)了catch_type所描述的異常類型御吞,那么將跳轉(zhuǎn)到handler_pc行繼續(xù)處理。
- attribute_count,屬性計數(shù)器漓藕,占有 2 個字節(jié)陶珠,表示Code屬性表的其他屬性的數(shù)目
- attribute_info,表示Code屬性表具有的屬性表,它主要分為兩個類型的屬性表:“LineNumberTable”類型和“LocalVariableTable”類型享钞。
- “LineNumberTable”類型的屬性表記錄著Java源碼和機器指令之間的對應(yīng)關(guān)系
- “LocalVariableTable”類型的屬性表記錄著局部變量描述
4.6.1.3 Code屬性長度
屬性長度索引用4個字節(jié)(u4)描述,對應(yīng)16進制0x000000EB揍诽,即十進制的235,表示屬性的長度占用235個字節(jié)
4.6.1.4 Code屬性max_stack
操作數(shù)棧深度的最大值用2個字節(jié)(u2)描述,對應(yīng)16進制0x002,即十進制的2,表示方法中操作數(shù)棧深度最大值為2
4.6.1.5 Code屬性max_locals
最大局部變量數(shù)目用2個字節(jié)(u2)描述,對應(yīng)16進制0x005栗竖,即十進制的5,表示最大局部變量數(shù)目為5
4.6.1.6 Code屬性code_length
java字節(jié)碼的長度用4個字節(jié)(u4)描述,對應(yīng)16進制0x0000003C暑脆,即十進制的60,表示ava字節(jié)碼的長度為60
4.6.1.7 Code屬性code
java字節(jié)碼的長度用60個字節(jié)描述
4.6.1.8 Code屬性中異常表集合
異常表集合的結(jié)構(gòu)被劃分為異常表數(shù)量和異常表集合。
異常表數(shù)量(exceptions_count):表示方法代碼中可能存在拋出異常個數(shù)狐肢。
異常表(exception_info):表示代碼中一個異常添吗。
4.6.1.8.1 Code屬性中異常表數(shù)量
Code屬性中異常表數(shù)量用2個字節(jié)(u2)描述,對應(yīng)16進制0x004,即十進制的4,表示異常表數(shù)量為4
4.6.1.8.2 Code屬性中異常表結(jié)構(gòu)
異常表用來表示的意思是:如果字節(jié)碼從第start_pc行到第end_pc行之間出現(xiàn)了catch_type所描述的異常類型份名,那么將跳轉(zhuǎn)到handler_pc行繼續(xù)處理碟联。
名稱 | 字節(jié)長度 | 含義 |
---|---|---|
start_pc | 2個字節(jié) | 異常發(fā)生起始字節(jié)指令行 |
end_pc | 2個字節(jié) | 異常發(fā)生結(jié)束字節(jié)指令行 |
handler_pc | 2個字節(jié) | 異常處理字節(jié)指令行 |
catch_type | 2個字節(jié) | 異常類型 |
異常發(fā)生起始字節(jié)指令行用2個字節(jié)(u2)描述,對應(yīng)16進制0x0000,即十進制的0,表示異常發(fā)生起始字節(jié)指令行為0
異常發(fā)生結(jié)束字節(jié)指令行用2個字節(jié)(u2)描述,對應(yīng)16進制0x000f僵腺,即十進制的15,表示異常發(fā)生結(jié)束字節(jié)指令行為15
異常處理字節(jié)指令行用2個字節(jié)(u2)描述,對應(yīng)16進制0x001A鲤孵,即十進制的26,表示異常處理字節(jié)指令行為26
異常類型用2個字節(jié)(u2)描述,對應(yīng)16進制0x0006,即十進制的6,6是常量池數(shù)組的一個下標(biāo)辰如,指向常量池中一個常量普监,通過對照javap中結(jié)果中對應(yīng)到一個CONSTANT_Utf8_info類型的常量(下標(biāo)#6),對應(yīng)字符串"java/lang/Exception"
這里同樣可以使用javap反編譯工具來解析獲取。我們在此比對下凯正,需要注意的是這里行表示的是反編譯工具中字節(jié)指令的行而非源代碼中的行毙玻。
stack=2, locals=5, args_size=1
0: iconst_1
1: istore_1
2: iconst_1
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: istore_3
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_3
12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
15: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
18: ldc #4 // String finally
20: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: goto 59
26: astore_1
27: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
30: ldc #7 // String catch
32: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
35: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
38: ldc #4 // String finally
40: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
43: goto 59
46: astore 4
48: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
51: ldc #4 // String finally
53: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
56: aload 4
58: athrow
59: return
Exception table:
from to target type
0 15 26 Class java/lang/Exception
0 15 46 any
26 35 46 any
46 48 46 any
對比源代碼
public class ClassStructureMethod {
public void greeting() throws Exception {
try {
int a=1;
int b=1;
int c=a+b;
System.out.println(c);
}catch (Exception e){
System.out.println("catch");
}finally {
System.out.println("finally");
}
}
}
code屬性其他異常如下
4.6.1.9 Code屬性中的屬性
code屬性內(nèi)部同樣有屬性集合
屬性表集合的結(jié)構(gòu)同樣被劃分為屬性表數(shù)量和屬性表集合。
屬性表數(shù)量(methods_count):表示方法中定義的屬性個數(shù)漆际。
屬性表(method_info):表示方法中定義某一個屬性淆珊。其中涵蓋了屬性的所有信息。
4.6.1.9.1 Code屬性中屬性類型
Code屬性中定義的屬性主要有“LineNumberTable”類型和“LocalVariableTable”類型
- “LineNumberTable”類型的屬性表記錄著Java源碼和機器指令之間的對應(yīng)關(guān)系
- “LocalVariableTable”類型的屬性表記錄著局部變量描述
4.6.1.9.2 Java虛擬機定義的LineNumberTable
attribute_name_index,屬性名稱索引奸汇,占有2個字節(jié)施符,其內(nèi)的值指向了常量池中的某一項,該項表示字符串“LineNumberTable”;
attribute_length,屬性長度擂找,占有 4個字節(jié)戳吝,其內(nèi)的值表示后面有多少個字節(jié)是屬于此LineNumberTable屬性表的;
line_number_table_length:描述line_number_table結(jié)構(gòu)的數(shù)量
line_number_table:用來描述一行Java源碼和機器指令之間的對應(yīng)關(guān)系
line_number_table結(jié)構(gòu)
名稱 | 字節(jié)長度 | 含義 |
---|---|---|
start_pc | 2個字節(jié) | 字節(jié)碼行號 |
line_number | 2個字節(jié) | java 源碼行號 |
4.6.1.9.3 Java虛擬機定義的LocalVariableTable
[圖片上傳失敗...(image-2d7657-1564563120952)]%20%E5%B1%9E%E6%80%A7.png)
attribute_name_index,屬性名稱索引贯涎,占有2個字節(jié)听哭,其內(nèi)的值指向了常量池中的某一項,該項表示字符串“LocalVariableTable”;
attribute_length,屬性長度塘雳,占有 4個字節(jié)陆盘,其內(nèi)的值表示后面有多少個字節(jié)是屬于此LineNumberTable屬性表的;
local_variable_table_length:描述local_variable_table結(jié)構(gòu)的數(shù)量
local_variable_table:項目代表了一個棧幀與源碼中的局部變量的關(guān)聯(lián)
local_variable_table結(jié)構(gòu)
start_pc 和 length 屬性:分別代表了 這個局部變量的生命周期開始的字節(jié)碼偏移量及其作用范圍長度败明,兩者結(jié)合起來就是這個局部變量在字節(jié)碼中的作用域范圍隘马;
name_index 和 desc_index: 都是指向常量池中 CONSTANT_Utf8_info 型常量的索引,分別代表了局部變量的名稱以及這個局部變量的描述符妻顶;
index:是這個局部變量在棧幀局部變量表中Slot的位置酸员。當(dāng)這個變量是 64 位類型時,它占用的Slot 為 index and index + 1;
LocalVariableTable屬性:它增加了一個姐妹屬性——LocalVariableTypeTable讳嘱,這個新增的屬性結(jié)構(gòu)與LocalVariableTable 非常相似幔嗦,僅僅是把記錄的字段描述符的desc_index 替換為字段的特征簽名,對于非泛型類型來說沥潭, 描述符和特征簽名能描述的信息是基本一致的邀泉,但是泛型引入后,由于描述符中泛型的參數(shù)化類型被擦除掉钝鸽,描述符就不能正確地描述泛型類型了汇恤,所以就引入了LocalVariableTypeTable了;
如果不太理解可以看下圖
4.6.1.9.4 Javap反編譯結(jié)果
LineNumberTable:
line 6: 0
line 7: 2
line 8: 4
line 9: 8
line 13: 15
line 14: 23
line 10: 26
line 11: 27
line 13: 35
line 14: 43
line 13: 46
line 15: 59
LocalVariableTable:
Start Length Slot Name Signature
2 13 1 a I
4 11 2 b I
8 7 3 c I
27 8 1 e Ljava/lang/Exception;
0 60 0 this Ljvm/ClassStructureMethod;
4.6.2 Exceptions 屬性
Exception屬性是在方法表中與Code屬性平級的一項屬性寞埠,切勿與Code屬性中的異常混淆焊夸。Exception屬性的作用是列舉出方法中可能拋出的受查異常(Checked Exception)仁连,也就是方法描述時在 throws 關(guān)鍵字后面列舉的異常。
Java虛擬機定義的Exceptions
attribute_name_index,屬性名稱索引,占有2個字節(jié)饭冬,其內(nèi)的值指向了常量池中的某一項使鹅,該項表示字符串“Exceptions”;
attribute_length,屬性長度,占有 4個字節(jié)昌抠,其內(nèi)的值表示后面有多少個字節(jié)是屬于此Exceptions屬性表的患朱;
number_of_exception:描述方法中可能拋出的受查異常的數(shù)量
exception_index_table:表示異常的名稱索引,其內(nèi)的值指向了常量池中的某一項炊苫,該項表示字符串對應(yīng)異常的名稱;
示例中Exceptions屬性
屬性名稱索引用2位字節(jié)(u2)來描述,對應(yīng)16進制0x001B裁厅,即十進制的27,27是常量池數(shù)組的一個下標(biāo)侨艾,指向常量池中一個常量执虹,通過對照javap中結(jié)果中對應(yīng)到一個CONSTANT_Utf8_info類型的常量(下標(biāo)#27),字符串值為"Exceptions"唠梨,表示屬性類型為"Exceptions"袋励。
屬性長度用4位字節(jié)(u4)來描述,對應(yīng)16進制0x00000004,即十進制的4当叭,表示"Exceptions"屬性值長度為4個字節(jié)
異常數(shù)量用2位字節(jié)(u2)來描述,對應(yīng)16進制0x0001茬故,即十進制的1,表示異常的數(shù)量為1
- 異常的名稱索引用2位字節(jié)(u2)來描述,對應(yīng)16進制0x0006蚁鳖,即十進制的6磺芭,8是常量池數(shù)組的一個下標(biāo),指向常量池中一個常量才睹,通過對照javap中結(jié)果中對應(yīng)到一個CONSTANT_Class_info類型的常量(下標(biāo)#6),CONSTANT_Class_info類型常量其值轉(zhuǎn)換為整數(shù)37徘跪,指向常量池中一個常量,通過對照javap中結(jié)果中對應(yīng)到一個CONSTANT_Utf8_info類型的常量(下標(biāo)#37)琅攘,字符串值為"java/lang/Exception"垮庐。
4 總結(jié)
可以用一張圖來描述上訴方法的結(jié)構(gòu)
javap完整結(jié)果
Classfile /C:/work/project/juc-in-action/target/classes/jvm/ClassStructureMethod.class
Last modified 2019-7-30; size 861 bytes
MD5 checksum c291986bf1b6bc3997d2e13aff91e614
Compiled from "ClassStructureMethod.java"
public class jvm.ClassStructureMethod
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #9.#30 // java/lang/Object."<init>":()V
#2 = Fieldref #31.#32 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Methodref #33.#34 // java/io/PrintStream.println:(I)V
#4 = String #35 // finally
#5 = Methodref #33.#36 // java/io/PrintStream.println:(Ljava/lang/String;)V
#6 = Class #37 // java/lang/Exception
#7 = String #38 // catch
#8 = Class #39 // jvm/ClassStructureMethod
#9 = Class #40 // java/lang/Object
#10 = Utf8 <init>
#11 = Utf8 ()V
#12 = Utf8 Code
#13 = Utf8 LineNumberTable
#14 = Utf8 LocalVariableTable
#15 = Utf8 this
#16 = Utf8 Ljvm/ClassStructureMethod;
#17 = Utf8 greeting
#18 = Utf8 a
#19 = Utf8 I
#20 = Utf8 b
#21 = Utf8 c
#22 = Utf8 e
#23 = Utf8 Ljava/lang/Exception;
#24 = Utf8 StackMapTable
#25 = Class #37 // java/lang/Exception
#26 = Class #41 // java/lang/Throwable
#27 = Utf8 Exceptions
#28 = Utf8 SourceFile
#29 = Utf8 ClassStructureMethod.java
#30 = NameAndType #10:#11 // "<init>":()V
#31 = Class #42 // java/lang/System
#32 = NameAndType #43:#44 // out:Ljava/io/PrintStream;
#33 = Class #45 // java/io/PrintStream
#34 = NameAndType #46:#47 // println:(I)V
#35 = Utf8 finally
#36 = NameAndType #46:#48 // println:(Ljava/lang/String;)V
#37 = Utf8 java/lang/Exception
#38 = Utf8 catch
#39 = Utf8 jvm/ClassStructureMethod
#40 = Utf8 java/lang/Object
#41 = Utf8 java/lang/Throwable
#42 = Utf8 java/lang/System
#43 = Utf8 out
#44 = Utf8 Ljava/io/PrintStream;
#45 = Utf8 java/io/PrintStream
#46 = Utf8 println
#47 = Utf8 (I)V
#48 = Utf8 (Ljava/lang/String;)V
{
public jvm.ClassStructureMethod();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Ljvm/ClassStructureMethod;
public void greeting() throws java.lang.Exception;
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=5, args_size=1
0: iconst_1
1: istore_1
2: iconst_1
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: istore_3
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_3
12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
15: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
18: ldc #4 // String finally
20: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: goto 59
26: astore_1
27: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
30: ldc #7 // String catch
32: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
35: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
38: ldc #4 // String finally
40: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
43: goto 59
46: astore 4
48: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
51: ldc #4 // String finally
53: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
56: aload 4
58: athrow
59: return
Exception table:
from to target type
0 15 26 Class java/lang/Exception
0 15 46 any
26 35 46 any
46 48 46 any
LineNumberTable:
line 6: 0
line 7: 2
line 8: 4
line 9: 8
line 13: 15
line 14: 23
line 10: 26
line 11: 27
line 13: 35
line 14: 43
line 13: 46
line 15: 59
LocalVariableTable:
Start Length Slot Name Signature
2 13 1 a I
4 11 2 b I
8 7 3 c I
27 8 1 e Ljava/lang/Exception;
0 60 0 this Ljvm/ClassStructureMethod;
StackMapTable: number_of_entries = 3
frame_type = 90 /* same_locals_1_stack_item */
stack = [ class java/lang/Exception ]
frame_type = 83 /* same_locals_1_stack_item */
stack = [ class java/lang/Throwable ]
frame_type = 12 /* same */
Exceptions:
throws java.lang.Exception
}
SourceFile: "ClassStructureMethod.java"