try-finally 字节码分析
我们都知道下面的代码返回值为8,下面通过字节码看下是怎么返回8的.
public int tryFinally(){ int i = 0; try{ i++; return i; }finally { i = 8; return i; } }
通过javap -v 命令输出字节码
public int tryFinally(); flags: ACC_PUBLIC Code: stack=1, locals=4, args_size=1 0: iconst_0 //表示将常量0加载到操作数栈 1: istore_1 //表示将栈顶数据存储到index为1的局部变量中, 我们姑且记做local1=0 2: iinc 1, 1 //将index为1的局部变量的值做自增操作,local1=1 5: iload_1 //将index为1的局部变量的值加载到操作数栈,即常量1入栈 6: istore_2 //将栈顶数据存储到index为2的局部变量, local2=1 7: bipush 8 //将常量8入栈 9: istore_1 //将栈顶值8存储到index为1的局部变量, local1=8 10: iload_1 //将index为1的局部变量的值加载到操作数栈,即8入栈 11: ireturn //正常返回(没有异常发生), 返回栈顶值8 12: astore_3 //从下面的异常表,可以看出,如果2~7发生异常,那么从12开始执行.此时将栈顶值存储到局部变量3 13: bipush 8 //常量值8入栈 15: istore_1 //将常量值8存储到局部变量1,即local1=8 16: iload_1 //局部变量1值加载到操作数栈,及常量8入栈 17: ireturn //返回栈顶值8 Exception table: //异常表 from to target type 2 7 12 any //表示如果2~7发生异常,那么从12开始执行 12 13 12 any //表示如果12~13发生异常,那么从12开始执行
从字节码我们可以看出无论try语句是否出现异常,finally语句块都会执行,根据字节码我们可以看出,最终返回的值无论是否发生异常都是返回8
加载指令
load
将一个局部变量加载到操作数栈的指令有:
iload, iload_<n>,lload,lload_<n>,fload,fload_<n>,dload,dload_<n>,aload,aload_<n>
其中load前面的i,l,f,d,a分别表示数值类型为i,long,float,double,引用类型.n表示在局部变量表中下标为n的局部变量
iload_1表示将局部变量表中下标为1的局部变量的值加载到操作数栈
常量入栈的jvm指令有:
bipush, sipush, ldc, ldc_w, ldc2_2,aconst_null, iconst_m1,iconst_<i>,lconst_<l>,fconst_<f>,dconst_<d>
iconst_m1 表示将常量-1入栈
iconst_<i> 表示将常量0~5入栈,iconst_0 表示将常量0入栈
bipush 表示将-128~127的整数入栈
sipush 表示将-32768~32767的整数入栈
lconst_<l>表示将long类型数常量入栈
fconst_<l>表示将flost类型常量入栈
dconst_<d>表示将double类型常量入栈
ldc 表示将字符串或者数值类型常量入栈
存储指令
store
将一个数值从操作数栈存储到局部变量表的指令有:
istore、istore_<n>、lstore、lstore_<n>、fstore、fstore_<n>、dstore、dstore_<n>、astore、astore_<n>
如istore_2 表示将操作数栈顶值存储到局部变量表中下标为2的类型为int的局部变量