public class Test {
public static void main(String[] args) {
int i = show();
System.out.println(i);
}
public static int show(){
int i = 10 ;
try{
return i;
} finally {
i = 32;
}
System.out.println("沒有執行到這裏....");
return i;
}
}
這裏需要思考幾個問題:
- 是不是執行到第一個return i ;就方法返回值並結束
- finally代碼塊是否執行了
- 是否打印了輸入的字符串
通過執行javap -v Test.class命令 可以查看class字節碼,下面只拿出了重點需要講解的show()方法
public static int show();
descriptor: ()I
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=3, args_size=0
0: bipush 10 //常量10壓入操作棧的棧頂
2: istore_0 //保存到局部變量表的slot_0中
3: iload_0 //加載slot_0的值10 載入到操作棧的棧頂
4: istore_1 //把當前操作數棧的棧頂值10又存放到了局部變量中slot_1的位置(沒有名字)
5: bipush //常量32壓入操作棧的棧頂
7: istore_0 //把棧頂的值32保存到局部變量表中slot_0的位置
8: iload_1 //加載slot_1元素的值10 載入到操作數棧的棧頂
9: ireturn //返回棧頂的10
10: astore_2 //根據異常表中的信息 發生異常則執行此處
11: bipush //常量 32 壓入操作棧的棧頂
13: istore_0 //保存到局部變量表的slot_0中
14: aload_2 //加載異常對象的引用
15: athrow //拋出異常
Exception table: //異常表 from to 表示捕獲字節碼中2-3的代碼,然後根據type類型進行匹配,如果匹配成功則執行第10的位置
from to target type
3 5 10 any
LineNumberTable:
line 11: 0
line 13: 3
line 15: 5
line 13: 8
line 15: 10
line 16: 14
LocalVariableTable:
Start Length Slot Name Signature
3 13 0 i I
StackMapTable: number_of_entries = 1
frame_type = 255 /* full_frame */
offset_delta = 10
locals = [ int ]
stack = [ class java/lang/Throwable ]
}
通過上面的分析可以看出 :當只有try塊中包含return,則先會把返回的值存放到一個臨時的局部變量表的位置,然後在執行finally塊中的代碼,雖然最終對i的值做了修改,但返回的值是之前已經臨時保存起來的,並不影響返回結果。
- 代碼在執行到try 裏面的return並沒有馬上結束方法
- finally語句總會執行
- 沒有打印輸入,說明在try 中的return在執行完finally代碼塊後就返回值並結束方法
public class Test {
public static void main(String[] args) {
int i = test() ;
System.out.println(i);
}
public static int test() {
int a = 10;
try {
int c = 1/0;
return a;
} catch (Exception e) {
a = 22;
return a ;
} finally {
a =33;
return a ;
}
}
}
通過字節碼的分析,大家通過測試還可以得出以下結論
- try catch finally中都包含return的時候,finally裏面的return最牛B,返回的是finally代碼塊裏面壓入操作棧的值
- finally中使用return語句,會屏蔽錯誤的發生,通過字節碼文件就會發現沒有了athrow這行指令