目录
背景:
目标:
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。
练习:
如果理解了,那么请看下一题:
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()一样的道理。
故结果是:
执行finally
19