目录

背景:

目标:

finally不执行:

finally执行:

结论:代码顺序走,finally必执行,先遇到return,副本把值存。

背景:

在异常这一章节中,finally到底什么时候执行,什么时候不执行,代码中有return还执不执行finally代码?

目标:

通过demo了解finally+return执行的过程与原理。真正理解并能判断段代码的返回结果。

finally不执行:

finally不执行的情况只有是程序奔溃,没有内存,断电的情况下才会不执行,以及在finally代码之前有System.exit(0);其它正常运行的代码只要写了finally都会执行;

finally执行:

代码正常运行都会执行finally里面的代码,现在我们要弄清楚的是在finally之前有return语句,该如何理解程序的流程以及返回值。

结论:代码顺序走,finally必执行,先遇到return,副本把值存。

下面我们来看一段代码,看看下面两个输出的值是多少?

System.out.println(test1());
System.out.println(test2().age);
//测试基本类型的情况
public static int test1(){
    int a = 17;
    try {
        return a;
    }catch (Exception e){
        return 0;
    }finally {
        a = 27;
        System.out.println("执行finally");
    }
}

//测试引用类型的情况
public static Person test2(){
    Person person = new Person();
    try{
        person.age = 18;
        return person;
    }catch (Exception e){
        return null;
    }finally {
        person.age = 28;
        System.out.println("执行finally");
    }
}

公布答案:

执行finally

17

执行finally

28

从答案上,我们可以看出,确实都执行了finally,和前面的赋值运算,只是基本类型和引用类型有区别,这和我们的Java虚拟机内存模型有关系。

解析:

在test1方法中,int a = 17; 定义a并赋值17,然后return会将栈中a=17保存至副本,准备返回。在finanlly进行修改a = 27,并没有修改副本中的内容;故返回17;

在test2方法中,Person person = new Person(); 定义一个person,会在堆中创建一个Person类的对象,并将堆中地址赋值给引用值person = 0x1234保存在栈中。程序中将person的age赋值,age=18,然后return会将栈中person = 0x1234保存至副本,准备返回。在finallt进行修改,地址为0x1234 person对象的age = 28;返回的应用值 person = 0x1234 没有变化,但是内容变化为28;故返回28。

print关键词java java关键字finally_java

 练习:

如果理解了,那么请看下一题:

System.out.println(test3().age);
public static Person test3(){
    Person person = new Person();
    try{
        person.age = 19;
        return person;
    }catch (Exception e){
        return null;
    }finally {
        person = new Person(29);
        System.out.println("执行finally");
    }
}

这段代码输出的年龄是多少?

分析:

同样的test3()创建了一个Person类的对象,会在堆中开辟一个空间来存储person对象信息,然后将地址0x1455赋值给person引用,并保存在栈中,在return之前赋值age=19,return时会创建一个副本person = 0x1455,然后在finally又新创建了一个对象,并把地址0x1456赋值给person引用,不过这时已经为时已晚,因为副本已经保存为person = 0x1455,算在finally在修改引用地址,副本也不会在改变,这和test1()一样的道理。

print关键词java java关键字finally_print关键词java_02

故结果是:

执行finally

19