前言
适合人群:具有一定jvm字节码基础,能看得懂字节码与理解异常表最好
我一般喜欢从宏观到微观,学习都是由宏入微,不会在微观做过多文章,但是会告诉大家是怎么去得到这些结论的,如何进入到微观世界。
情景
先看以下这个最普通不过的try-catch-finally结构
try {
代码块A;
return x;
}catch (Exception e){
代码块B;
return x;
}finally {
代码块D;
}
对于程序员而言,finnally代码块D的执行非常显然,当然是无论上面是正常抑或是异常,最终都会执行代码块D;但是对于JVM又如何去保证我们所感受的这样呢?
原理
其实一张图一蔽之:
从上图来看,哪怕不知道异常表是什么,不知道多出来的C为何物,也能一眼看出,大概的意思就是,把代码块D插入到A和return之间,B和return之间,意思就是类似于这样:
try {
代码块A;
代码块D;
return x;
}catch (Exception e){
代码块B;
代码块D;
return x;
}
注意,这里只是说”类似“,因为实际情况代码块D还插入到另一个代码块C与throw之间,至于C是什么东西,就是编译器会生成一段当发生没有捕捉的异常的时候的代码块C,也就是说发生了catch不到的异常就会去执行C
其实说到这里就够了,但是小伙伴又如何自己看到真相呢?想知道的那就往下继续看吧,不过可能需要一点基础知识
证明
工具:用IDEA的插件搜索bytecode,安装bytecode或者bytecode with jclasslib,然后重启IDEA在左上角的tab栏目里的view->show bytecode/bytecode with jclasslib,就可以看字节码了。
先写一段代码:
public static int test1() {
int i = 1;
try {
return i;
}catch (Exception e){
e.printStackTrace();
return 0;
}finally {
System.out.println("good job");
}
}
我们来看看它的字节码:
至于看字节码好像执行顺序是A-D-B-D-C-D有木有?那么发生异常的时候又是如何跳转的呢?其实这是JVM的基础,在栈帧里有异常表,记录着异常发生时的跳转情况:
然后再回过头看最开始的那张图(顶上一张异常表,下面是ABCD代码块的),是不是搞清楚finally的底层原理呢?
最后
希望大家能看懂,如果没看懂的话,那就再列举一下所需具备的工具与知识:1.jclasslib bycode插件 2.简单阅读字节码的能力 3.理解异常表的作用 4.简单区分前端编译器与jvm的作用