java中的tycatchfially(Java中的Bea是什么)
导语:java中的try catch finally return
先上代码
public class TestReturn { public int testReturn(int a) { try { return a; } finally { a++; } } public static void main(String[] args) { System.out.println(new TestReturn().testReturn(1)); }}
代码很简单,输出结果为啥呢?1 or 2?
这是一道经常在笔试中考的java基础问题,这次我们从字节码的角度来分析一下,return究竟return了啥。
我们用javap -v命令对class文件进行反编译,得到如下描述(抽取方法部分):
字节码其实就是用jvm的指令(200多个)对栈和局部变量表的操作。
继续分析字节码:
初始值:栈顶:空,局部变量表:[this,1,...]
第六行:0: iload_1,iload是一个操作指令,表示加载局部变量表下标为1的值到栈顶,因为是普通方法,0放的是this对象,1放的是第一个入参,i表示此参数为int类型,iload_1表示把第一个入参加载到栈顶。
栈顶:1,局部变量表:[this,1,...]
第七行:1: istore_2,istore也是一个jvm指令,把栈顶值弹出存放到局部变量表下标为2的位置。
栈顶:空,局部变量表:[this,1,1,...]
第八行:2: iinc 1, 1,iinc是一个自增指令, 是对局部变量表里的内容做自增,参数1, 1表示在局部变量表的下标为1的值+1。
栈顶:空,局部变量表:[this,2,1,...]
第九行:5: iload_2,加载局部变量表下标为2的值到栈顶。
栈顶:1,局部变量表:[this,2,1,...]
第十行:6: ireturn,栈顶弹出返回,此时栈顶的值为1,所以返回值为1。
程序的主体部分到这里就结束了,但是我们发现下面还有好几行指令是在干嘛呢?
Exception table: from to target type 0 2 7 any
Exception table: from to target type 0 2 7 any
先来看看这个Exception table,我们源代码里并没有写catch,但是javac编译器却帮我们自动生成了异常表,from,to表示需要对哪部分指令做异常捕获,这里的值是0,2,意思就是在对:
0: iload_1 1: istore_2 2: iinc 1, 1
这几个指令操作做捕获,如果这几个指令抛出了异常,程序跳到target 7,也就是第七行指令:
7: astore_3 8: iinc 1, 1 11: aload_3 12: athrow
下面来分析一下抛异常的时候的执行指令:
astore_3:a表示是一个对象,此处为异常对象,把异常对象存储到局部变量表的3号下标位置。
栈顶:1,局部变量表:[this,1,1,exception...]
iinc 1, 1:对局部变量表1位置的值加1
栈顶:1,局部变量表:[this,2,1,exception...]
aload_3:加载局部变量表3位置的值到栈顶
栈顶:exception,局部变量表:[this,2,1,exception...]
athrow:弹出栈顶,并抛出栈顶的异常对象
整个流程用伪代码来说就像下面这样:
总结:
我们通过分析class文件可以很清楚的发现:
1,有try块的程序无论有没有catch,在字节码层面都会被拆解成2部分,正常部分和异常处理部分,finally块的程序会被分别插入到这2部分之中,所以finally关键字其实只是一个语法糖。
2,对于自增操作其实是操作的局部变量表,而返回值返回的是栈顶的值,关键点是要看局部变量表在函数返回之前有没有被load到栈顶。
本文内容由小舻整理编辑!