本次文章中所有反汇编所用版本均为1.8
我们都知道finally是不管是否有异常都一定会执行的代码段
他的内部其实是通过调整goto指令跳转的位置来实现的
代码如下
public void testForFinally() {
try {
System.out.println(2);
} finally {
System.out.println(1);
}
}
反汇编如下
stack=2, locals=2, args_size=1
0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
3: iconst_2
4: invokevirtual #21 // Method java/io/PrintStream.println:(I)V
7: goto 20
10: astore_1
11: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
14: iconst_1
15: invokevirtual #21 // Method java/io/PrintStream.println:(I)V
18: aload_1
19: athrow
20: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
23: iconst_1
24: invokevirtual #21 // Method java/io/PrintStream.println:(I)V
27: return
他在调用玩syso后跳转的不是27(如上代码,goto 20),而是跳转到20,执行的是finally的代码
因为变量的生命周期,finally的代码块和try代码块不是一个代码块,所以里面的变量在代码块结束后下一个变量使用时被清空了。
而如果代码没有finally的情况下,是直接跳转到return的
这就是为什么finally一定会执行
异常表
扫描二维码关注公众号,回复:
2783419 查看本文章
代码如下
public void testForException() {
try {
System.out.println(2);
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
反汇编如下
stack=2, locals=2, args_size=1
0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
3: iconst_2
4: invokevirtual #21 // Method java/io/PrintStream.println:(I)V
7: goto 23
10: astore_1
11: aload_1
12: invokevirtual #27 // Method java/lang/NullPointerException.printStackTrace:()V
15: goto 23
18: astore_1
19: aload_1
20: invokevirtual #32 // Method java/lang/Exception.printStackTrace:()V
23: return
Exception table:
from to target type
0 7 10 Class java/lang/NullPointerException
0 7 18 Class java/lang/Exception
这里最下方有一个异常表,表示抓取的行号,target是exception中执行代码的起始地址,exception处理完后是一个goto
如果只有一个异常的时候是没有goto的,exception指令执行完后直接是return