你敢说你会finally吗

本文解析了Java中finally块的执行机制及对变量的影响,并通过字节码解释了为何finally块中的修改不会影响已返回的值。

昨天在通过jvm规范搞懂了java中类循环依赖的编译问题,讨论见

http://topic.youkuaiyun.com/u/20111008/11/aede24de-a712-470c-9315-8796301c548f.html

然后突发奇想想了解下java的异常处理原理,只是略微看懂了finally,下面是个人关于一个网上小问题的见解,欢迎各位指正


public class Exception2 {

    int x = 1;

    public static void main(String args[]){
        Exception2 e = new Exception2();
        System.out.println(e.getValue());
        System.out.println(e.x);
        System.out.println(e.xx());
    }

    int getValue(){
        try{
            return x;
        }finally{
            x = 2;
        }
    }

    int xs(){
        return x;
    }

    int xx(){
        x = 2;
        return x;
    }
}


打印出的值分别为 1,2,2


第一个值之所以为1,见下面字节码

int getValue();
  Code:
   0:   aload_0
   1:   getfield        #2; //Field x:I
   4:   istore_1        //本来是要直接return的,但是因为finally的存在,保存当前状态,并之后执行finally块中的代码
<<<5:   aload_0                 
   6:   iconst_2
>>>7:   putfield        #2; //Field x:I
   10:  iload_1         //iload_1 对应istore_1时保存进去的值,即在第一行中调用getfield得到的1            
   11:  ireturn
   12:  astore_2        //保存现场, 即执行到什么地方
   13:  aload_0
   14: iconst_2
   15: putfield #2; //Field x:I 18: aload_2 //恢复现场 
   19: athrow
   Exception table: 
   from to target type 
     0 5 12 any 
     12 13 12 any
  int xs();
  Code: 
   0: aload_0 
   1: getfield #
   2; //Field x:I 
   4: ireturn
   int xx(); 
   Code:
   0: aload_0
   1: iconst_2
   2: putfield #2; //Field x:I
   5: aload_0 
   6: getfield #2; //Field x:I 
   9: ireturn}
<<<Code....>>>中的代码时x=2对应的字节码.可以发现xx方法在ireturn之前执行了getfield方法,所以返回的是更改后的值而getValue方法中没有在return前重新getfield,故为1猜测,之所以能保证finally一定会被执行到,是因为当java在检测try中的return后,就将finally中的代码插入了return之前,之前是loadx->return,插入之后变为loadx->finally block->return。java并没有做额外的工作去重新load x的值,即便

x在finally block中被改变了

下面是引用到的一点jvm指令的知识

aload_0:aload_0 is supposed to push 'this' on to the stack.Not quite … aload_0 reads the first argument of the method. In member functions, this happens to be the this reference. But main is not a member function, it’s astatic function so there is no this argument, and the true first argument of themethod is args.ireturn:Pops an int from the top of the stack and pushes it onto the operand stack of the invokerathrow:https://www.vmth.ucdavis.edu/incoming/Jasmin/ref-athrow.htmlputfield:putfield sets the value of the field identified by <field-spec> in objectref(a reference to an object) to the single or double word value on the operand stack

顺便附上一些指令的含义:(聪明的读者一定能推断出i代表int,f代表fload,d代表double,a代表引用类型)

istore x: 将int型变量存到本地变量. x代表一个本地变量地址号. 如istore 即将int型变量存到本地变量4去。

iload x: 将制定的int型变量x推送至栈顶。aload_0是指拿到this。

iconst x: 将int型常量推送至栈顶。

ireturn: 故名思议,从方法返回int,一般在返回之前都会iload一下,然后再从栈顶中取值返回。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值