论坛首页 入门技术论坛

finally 和 return

浏览 6056 次
精华帖 (0) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-08-27   最后修改:2009-08-27
分别写出下面的输出结果:
第一个:
public static int test() {
    int j = 0;
    try {
        j = 1;
        System.out.println("try:" + j);
        return j;
    }catch (Exception e) {
        // TODO: handle exception
    }finally {
        j = 2;
        System.out.println("finally:" + j);
    }
    return j;
}


第二个:
public static Person testPerson(Person p) {
    try {
        p.name = "try";
        return p;
    }catch (Exception e) {
        // TODO: handle exception
    }finally {
        p.name = "finally";
    }
		
    p.name = "last";
    return p;
}

class Person {
    String name;
	
    Person(String name) {
        this.name = name;
    }
}


想想答案,运行后核对。你做对了玛?
   发表时间:2009-08-31  
http://rednaxelafx.iteye.com/blog/189908
0 请登录后投票
   发表时间:2009-08-31  
iaimstar 写道


呵呵 这个是我在项目中发现的一个bug 如果没有认真看和对finally有了解 还真不容易发现
0 请登录后投票
   发表时间:2009-08-31   最后修改:2009-08-31
这里要理解的是return操作是一个压栈的操作(这里是方法的调用,就是把一个方法的栈顶值拷贝到调用方法的栈顶。注:每个方法都有自己的栈)
这里还要区分的一点是 值类型 和引用类型
另一点要理解的就是finally这个关键字的特性,主要就是它是作为单独的例程来运行的,同时要注意它指令执行的不对称性就可以了。
对于值类型,java虚拟机调用jsr指令,在执行finally一开始 就拷贝一个副本到另外一个地址(不是一开始j使用的地址),在finally正常执行结束后,调用ret指令把该值拷回栈顶。所以在finally中在对j进行操作是改变不了j的值的。
而如果是引用类型,由于拷贝的都是地址,因此对于对象的改变,这些地址肯定还是指向改变后的对象的(同一个对象)

令:第二个例子中 try中有了return了,下面在改变也没有用了,不会执行

深入JVM中专门有一章讲解了finally
0 请登录后投票
   发表时间:2009-08-31  
jiyanliang 写道
这里要理解的是return操作是一个压栈的操作(这里是方法的调用,就是把一个方法的栈顶值拷贝到调用方法的栈顶。注:每个方法都有自己的栈)
这里还要区分的一点是 值类型 和引用类型
另一点要理解的就是finally这个关键字的特性,主要就是它是作为单独的例程来运行的,同时要注意它指令执行的不对称性就可以了。
对于值类型,java虚拟机调用jsr指令,在执行finally一开始 就拷贝一个副本到另外一个地址(不是一开始j使用的地址),在finally正常执行结束后,调用ret指令把该值拷回栈顶。所以在finally中在对j进行操作是改变不了j的值的。
而如果是引用类型,由于拷贝的都是地址,因此对于对象的改变,这些地址肯定还是指向改变后的对象的(同一个对象)

令:第二个例子中 try中有了return了,下面在改变也没有用了,不会执行

深入JVM中专门有一章讲解了finally


那本书我是我计划中要看的书,但一直没找到合适的时间。
最近在找工作,郁闷的够呛 - -
0 请登录后投票
   发表时间:2009-08-31   最后修改:2009-08-31
jiyanliang 写道

令:第二个例子中 try中有了return了,下面在改变也没有用了,不会执行

会执行

ps:
第一个例子返回的结果是1,但是finally里面有return j的话会得到 返回结果为2
第二个例子中name返回值结果应该是finally
0 请登录后投票
   发表时间:2009-08-31   最后修改:2009-08-31
iaimstar 写道
jiyanliang 写道

令:第二个例子中 try中有了return了,下面在改变也没有用了,不会执行

会执行

ps:
第一个例子返回的结果是1,但是finally里面有return j的话会得到 返回结果为2
第二个例子中name返回值结果应该是finally

不好意思 我没有说明白。finally是不管怎么样都要执行的,我说的是
p.name = "last";   
return p;

这句,他没有执行
0 请登录后投票
   发表时间:2009-08-31  
jiyanliang 写道
这里要理解的是return操作是一个压栈的操作(这里是方法的调用,就是把一个方法的栈顶值拷贝到调用方法的栈顶。注:每个方法都有自己的栈)
这里还要区分的一点是 值类型 和引用类型
另一点要理解的就是finally这个关键字的特性,主要就是它是作为单独的例程来运行的,同时要注意它指令执行的不对称性就可以了。
对于值类型,java虚拟机调用jsr指令,在执行finally一开始 就拷贝一个副本到另外一个地址(不是一开始j使用的地址),在finally正常执行结束后,调用ret指令把该值拷回栈顶。所以在finally中在对j进行操作是改变不了j的值的。
而如果是引用类型,由于拷贝的都是地址,因此对于对象的改变,这些地址肯定还是指向改变后的对象的(同一个对象)

令:第二个例子中 try中有了return了,下面在改变也没有用了,不会执行

深入JVM中专门有一章讲解了finally

《Inside the Java Virtual Machine》的第二版已经很老了……从现状来看它已经老到足以误导人。
这里
引用
Bug 4381996 fixed: javac no longer generates the jsr instruction, instead inlining the finally clause.

于是Sun的javac从1.4.2开始就已经不生成JSR指令了。不然大家可以试试拿楼主的代码编译后javap看看。

hmm……大家继续讨论~
0 请登录后投票
   发表时间:2009-08-31   最后修改:2009-08-31
恩 确实如楼上所说。
之前看过inline方面的资料,竟然没有引起偶的重视。
0 请登录后投票
   发表时间:2009-09-01  
第二个可以理解,第一个不太懂。
为什么我debug的时候两次到达try语句中的return j; 这句话上面,而且j的值也改变了(第一次是1,第二次是2),最后居然还是返回了1。不懂。

而且jiyanliang说"这里要理解的是return操作是一个压栈的操作(这里是方法的调用,就是把一个方法的栈顶值拷贝到调用方法的栈顶。注:每个方法都有自己的栈)"。但是这个try/catch不是在同一个方法里面吗,怎么说每个方法都有自己的栈呢?
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics