Topic: finally子句和try子句中return的先后关系 |
Print this page |
1.finally子句和try子句中return的先后关系 | Copy to clipboard |
Posted by: zcjl Posted on: 2005-09-05 23:49 这个问题起因于java区基础版块的一篇帖子: http://community.csdn.net/Expert/topic/3636/3636856.xml?temp=.9524347 下面是我从《深入Java虚拟机 2E》(中文版,曹晓钢 蒋靖译)中得到的解释 由于现学现卖,不免有大量摘抄的地方,望诸位谅解。 jsr指令是使java虚拟机跳转到微型子例程[注释1]的操作码,另外一条指令使jsr_w,后者支持比前者更长的操作数(4个字节长)。当java虚拟机遇到jsr或是jsr_w指令,它会把返回地址压入栈,然后从微型子例程的开始处继续执行。 微型子例程执行完毕后(这里指的是finally子句中最后一条语句正常执行完毕,不包括抛出异常,或执行return、continue、break等情况),将调用ret指令,ret指令的功能是执行从子例程中返回的操作。 你也许会认为,ret指令应当从栈中弹出返回地址,因为返回地址也已被jsr指令压入栈。不是这样的,ret指令并不会这样做。在每一个子例程的开始处,返回地址都从栈顶端弹出,并且存储在局部变量中,稍后,ret指令将会从这个局部变量中取出返回地址。这种对返回地址的不对称的工作方式是必要的,因为finally子句本身会抛出异常或者含有return、break、continue等语句。由于这些可能性的存在,这个被jsr指令压入栈的额外返回地址必须立即从栈中移除。因此,当finally子句通过break、continue、return或者抛出异常退出时,这个问题就不必再考虑了。 先看主帖里的示例代码(为了bytecode的清晰,去掉了无关的打印语句和捕获异常语句)
//调用javap -c Test1后得到的字节码序列
------------------------------------------------------------------ 上面的中文注释,直接对应在指令后面的是《深入java虚拟机》中的指令说明,其下的才是我所理解的行为。 可以看出,源代码中简单的一句return b = 88;语句,编译成bytecode后,对应了3-12条指令。其中指令8是一个分界点,指令3-7执行b = 88这个语句,且赋值运算后将b的值和方法的返回值分别存入到位置为0和1的局部变量中,指令11、12则从位置为1的局部变量中取出方法的返回值,并返回。指令8则是将自己的偏移地址压入栈,然后跳转到指令19,开始执行finally子句。 finally子句先将指令8的偏移地址弹出栈,并保存到位置为3的局部变量中,然后开始执行后面的语句。当后面的语句执行完毕,通过指令51,从位置为3的局部变量中取出指令8的偏移地址,然后返回执行指令8的后续指令(try子句中最终的return指令)。 注释: 1.字节码中的finally子句在方法内部的表现很像“微型子例程”,因此本文中的“微型子例程”特指finally子句。 |
2.Re:finally子句和try子句中return的先后关系 [Re: zcjl] | Copy to clipboard |
Posted by: wmgreat Posted on: 2005-09-06 20:39 在Practical Java中第23条专门说明这一点,return语句如果在try中的话,当执行完return语句后执行权跳转到finally中,这里也是经常会出问题的地方。可以比较下面两端程序: public class Test{ |
Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1 客服电话 18559299278 客服信箱 714923@qq.com 客服QQ 714923 |