字节码中的finally子句在方法内部的表现很像“微型子例程”,每个try语句块与其后面的结尾处都会调用finally子例程,finally子句结束后,隶属于这个finalyy子句的微型子例程执行返回操作,程序在第一次调用微型子例程的地方继续执行后面的语句。
jsr 跳转到子例程
jsr ,branchbyte1,branchbyte2
1.Java虚拟机首先将紧随jsr指令后的一个字长的的操作码地址(程序计数器)压入操作数栈
2.通过计算{(branchbtye1<<8)|branchbyte2 }来给定一个带符号16位偏移量
3.计算得出的偏移量加到jsr操作码上,虚拟机计算出目标(程序计算器)地址,
4.虚拟机跳转到目标位置,在新位置上执行操作。
jsr_w
jsr_w branchbyte1,branchbyte2,branchbyte3,branchbyte4
计算(branchbyte1<<24)|(branchbyte2<<16)|(branchbyte3<<8)|branchbyte4得到一个带符号的 32位偏移量
ret从子例程中返回
ret,index
1.从程序计数器设为存储在indext指定的局部变量中的returnAdress值
2.从returnAddress继续执行
当finally子句通过break,continue,return或者抛出异常退出时,被jsr指令压入的额外返回地址将从栈中移除,这时候ret将不再会被执行
一个finally子句退出有两种方式:1,ret退出,然后执行后面的;2.break,continue,return退出,此时不再执行后面子句
public boolean test(){
try{
return true;
}finally{
break;
}
}return false;
}
此时return true不再执行,方法返回false;
每次进入finally前,先保存变量到局部变量,然后在执行完finally子句后,再从局部变量中获取值,然后使用
每次从finally返回的是保存的局部变量值,除非finally中有自己的返回语句(详见深入Jvm327)
public int test(boolean bVal){
try{
if(bVal){
return 1;
}
return 0;
}
finally{
System.out.println("sd")
}
0 iload_0 获取vVal值
1 ifeq 11 if判断
4 iconst_1 压入1到栈
5 istore_1 存储局部变量1
6 jsr 24 finally子例程跳转
9 iload_1 获得局部变量1
10 ireturn 返回局部标量1中的值
11 iconst_0 压入1 (if分支)
12 istore_1 存储局部变量1
13 jsr 24 条状子例程
16 iload_1 获取局部变量
17 ireturn 返回
18 astore _2 存储
19 jsr24
22aload_2
23 athrow 异常
子例程
24 astore_3 保存跳转地址到局部变量3中
25 getstatic#7
28ldc#1
30invokevirtual #8
33ret 3 返回到局部变量3保存的位置中
jsr包括三个jsr条状:if判断2个和一个异常捕获