- 源碼
TestClass.java
public class TestClass { public int inc() { int x; try { x=1; return x; }catch (Exception e){ x=2; return x; }finally { x=3; } } }
- jdk1.7編譯出來的
TestClass.class的class文件結(jié)構(gòu)
Classfile /root/IdeaProjects/java7_test/out/production/java7_test/org/fenixsoft/clazz/TestClass.class Last modified Feb 28, 2019; size 601 bytes MD5 checksum 495c52e30f4cf72096d5092696baf0b4 Compiled from "TestClass.java" public class org.fenixsoft.clazz.TestClass SourceFile: "TestClass.java" minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #4.#23; // java/lang/Object."<init>":()V #2 = Class #24; // java/lang/Exception #3 = Class #25; // org/fenixsoft/clazz/TestClass #4 = Class #26; // java/lang/Object #5 = Utf8 <init>; #6 = Utf8 ()V; #7 = Utf8 Code; #8 = Utf8 LineNumberTable; #9 = Utf8 LocalVariableTable; #10 = Utf8 this; #11 = Utf8 Lorg/fenixsoft/clazz/TestClass;; #12 = Utf8 inc; #13 = Utf8 ()I; #14 = Utf8 x; #15 = Utf8 I; #16 = Utf8 e; #17 = Utf8 Ljava/lang/Exception;; #18 = Utf8 StackMapTable; #19 = Class #24; // java/lang/Exception #20 = Class #27; // java/lang/Throwable #21 = Utf8 SourceFile; #22 = Utf8 TestClass.java; #23 = NameAndType #5:#6; // "<init>":()V #24 = Utf8 java/lang/Exception; #25 = Utf8 org/fenixsoft/clazz/TestClass; #26 = Utf8 java/lang/Object; #27 = Utf8 java/lang/Throwable; { public org.fenixsoft.clazz.TestClass(); 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 Lorg/fenixsoft/clazz/TestClass; public int inc(); flags: ACC_PUBLIC Code: stack=1, locals=5, args_size=1 0: iconst_1 1: istore_1 2: iload_1 3: istore_2 4: iconst_3 5: istore_1 6: iload_2 7: ireturn 8: astore_2 9: iconst_2 10: istore_1 11: iload_1 12: istore_3 13: iconst_3 14: istore_1 15: iload_3 16: ireturn 17: astore 4 19: iconst_3 20: istore_1 21: aload 4 23: athrow Exception table: from to target type 0 4 8 Class java/lang/Exception 0 4 17 any 8 13 17 any 17 19 17 any LineNumberTable: line 8: 0 line 9: 2 line 14: 4 line 10: 8 line 11: 9 line 12: 11 line 14: 13 LocalVariableTable: Start Length Slot Name Signature 2 6 1 x I 9 8 2 e Ljava/lang/Exception; 11 6 1 x I 0 24 0 this Lorg/fenixsoft/clazz/TestClass; 21 3 1 x I StackMapTable: number_of_entries = 2 frame_type = 72 /* same_locals_1_stack_item */ stack = [ class java/lang/Exception ] frame_type = 72 /* same_locals_1_stack_item */ stack = [ class java/lang/Throwable ] }
- 步驟說明表
說明1:由于
棧深度(max_stack,其實(shí)就是最大Slot數(shù))為1(),所以用1個中括號表示,棧頂是最右邊;最大本地變量(max_locals,單位也是Slot)為5,所以用5個中括號表示,排序從左到右從0開始。
說明2:由于本地變量是有作用域的,所以作用域之外本地變量會空著
說明3:局部變量表中第0個Slot放的L是this(即本方法所屬對象的引用)
說明4:如果不確定Slot中是否有值,那么會用?表示。
| 指令行號 | 指令 | 說明 | 本條指令執(zhí)行完之后棧 | 本條指令執(zhí)行完之后本地變量表 | 本條指令執(zhí)行完之后本地變量 | 備注 |
|---|---|---|---|---|---|---|
| 這是還沒執(zhí)行指令的狀態(tài) | [] | [L][][][][] | this | |||
| 0 | iconst_1 | 把int類型值1壓入棧頂 | [1] | [L][][][][] | this | |
| 1 | istore_1 | 彈出棧頂?shù)膇nt類型放入本地變量表第1個Slot | [] | [L][1][][][] | this | 即x=1 |
| 2 | iload_1 | 把本地變量表的第一個Slot中的int類型的值壓入棧頂 |
[1] | [L][1][][][] | this,x | 根據(jù)1、2發(fā)現(xiàn),x=1這條代碼并不是x的作用域,也就是說一個變量的作用域不是它被賦值的時候。根據(jù)測試得知一般賦值的下一行代碼就是作用域的開始 |
| 3 | istore_2 | 彈出棧頂?shù)膇nt類型放入局部變量表的第二個Slot中 |
[] | [L][1][1][][] | this,x | 根據(jù)1、3可知局部變量表被使用的時候,并不一定需要變量名:1中第一個Slot沒有變量名,但它有值;2中第二個Slot沒有變量名,但它有值。這里的第二個Slot是臨時存放return返回值的,它是有可能被其他局部變量覆蓋的。 |
| 4 | iconst_3 | 把int類型值3壓入棧中 | [3] | [L][1][1][][] | this,x | |
| 5 | istore_1 | 彈出棧頂int類型存入本地變量表第一個Slot | [] | [L][3][1][][] | this,x | 即x=3 |
| 6 | iload_2 | 把本地變量表第二個Slot壓入棧中 | [1] | [L][3][1][][] | this,x | |
| 7 | ireturn | 彈出棧頂int類型并存入返回值,返回方法 | [] | [L][3][1][][] | this,x | 即return x
|
從8開始是catch的代碼,首先會給Exception e變量賦值,本步驟就是把異常引用壓入棧頂,后面L代表引用 |
[L] | [L][?][?][][] | ||||
| 8 | astore_2 | 把棧頂引用存入局部變量表第二個Slot | [] | [L][?][L][][] | this | 即Exception e=?,因?yàn)?code>catch里面不需要第二個Slot中臨時存放的return返回值了,所以直接覆蓋了 |
| 9 | iconst_2 | 把int類型值2壓入棧 | [2] | [L][?][L][][] | this,e | |
| 10 | istore_1 | 彈出棧頂int類型存入局部變量表第一個Slot | [L] | [L][2][L][][] | this,e | 即x=2
|
| 11 | iload_1 | 把第一個Slot中的int類型壓入棧 | [2] | [L][2][L][][] | this,e,x | |
| 12 | istore_3 | 彈出棧頂元素放入局部變量表第三個Slot中 | [] | [L][2][L][2][] | this,e,x | 第三個Slot臨時存放return返回值
|
| 13 | iconst_3 | 把int類型值3壓入棧 | [3] | [L][2][L][2][] | this,e,x | |
| 14 | istore_1 | 彈出棧頂?shù)膇nt類型存入局部變量表第一個Slot | [] | [L][3][L][2][] | this,e,x | 即x=3 |
| 15 | iload_3 | 把第三個Slot中的int類型壓入棧 | [2] | [L][3][L][2][] | this,e,x | |
| 16 | ireturn | 彈出棧頂int類型并存入返回值,返回方法 | [] | [L][3][L][2][] | this,e,x | 即return x
|
從17開始是除了Exception或其子類的其他異常,即上面的any,本步驟就是把異常引用壓入棧頂 |
[L] | [L][?][?][?][] | this | |||
| 17 | astore 4 | 彈出棧頂引用類型存入局部變量表第四個Slot | [] | [L][?][?][?][L] | this | 這里并沒有把第三個Slot中的臨時return返回值覆蓋,難道是因?yàn)樗鼈兌际菦]名字的變量? |
| 19 | iconst_3 | 把int類型值3壓入棧頂 | [3] | [L][?][?][?][L] | this | |
| 20 | istore_1 | 彈出棧頂int類型存入本地變量表第一個Slot | [] | [L][?][?][?][L] | this,x | 即x=3 |
| 21 | aload 4 | 把第四個Slot中的引用壓入棧 | [L] | [L][?][?][?][L] | this,x | |
| 23 | athrow | 拋出異常 | 根據(jù)21、23,這就是把異常壓入棧拋給更高一級了 |
-
Exception table說明
根據(jù)java class.類結(jié)構(gòu).method中
異常表結(jié)構(gòu)可知:
try中出現(xiàn)Exception或其子類的異常,就轉(zhuǎn)到catch中處理
try中出現(xiàn)其他異常,就轉(zhuǎn)入finally處理
catch中出現(xiàn)任何異常(包括Exception或其子類),轉(zhuǎn)入finally處理
最后一個可以不管