Java语言中try-catch-finally中return解析以及引用类型和值类型区分

时间:2021-12-07 18:22:44

不管在try中还是catch中有没有return语句,finally中的代码是一定要执行的。话不多说,先上代码。

TEST 1:

private static int test1(){
int a = 0;
try{
return a;
}
finally{
a = 1;
System.out.println("finally running, a = " + a);
}
}
public static void main(String[] args) {
System.out.println("main running return a is "+test1());
}

执行结果是

finally running, a = 1
main running return a is 0

结论:在try中执行了return,finally中的代码还会执行,并且如果返回变量是int(值数据类型),finally中代码不会对返回值产生影响。

TEST 2:

private static int test2(){
int a = 0;
try{
return a;
}
finally{
a = 1;
System.out.println("finally running, a = " + a);
return a;
}
}
public static void main(String[] args) {
System.out.println("main running return a is "+test2());
}

执行结果

finally running, a = 1
main running return a is 1

结论:在try中执行了return,finally中的代码还会执行,并且如果finally中也有return语句,则覆盖了try中的return语句。

另外return语句在catch中也是类似,在catch中return,有finally仍然执行,如果finally中有return则覆盖catch的return,不再赘述。

在事例代码1中提到了“值数据类型”(java中的八大基本数据类型),相对的是“引用数据类型”。在这里会有什么差别呢?
观察下面代码:
TEST 3:

private static StringBuffer test3(){
StringBuffer a = new StringBuffer("xxx");
try{
return a;
}
finally{
a.append("yyy");
System.out.println("finally running, a = " + a);
}
}

public static void main(String[] args) {
System.out.println("main running return a is "+test3());
}

输出结果

finally running, a = xxxyyy
main running return a is xxxyyy

对比TEST 1 的运行结果,为什么int类型中函数的返回值和finally输出的值不一样而在TEST 3 中就一样了呢?
原因就是int是基本数据类型,try中return的时候会复制一个int类型的临时变量,所以在finally中再改变a的值对try中return临时变量的值没有影响。而StringBuffer是引用类型的变量,虽然在try中return的时候也会复制一个StringBuffer类型的引用(记为temp),但是temp和a指向的是同一个对象,所以finally通过引用a改变了内容,返回的temp引用的内容也发生了变化。
再观察以下代码:
TEST 4:

    private static String  test4(){
String a = "xxx";
try{
return a;
}
finally{
a+="yyy";
System.out.println("finally running, a = " + a);
}
}

public static void main(String[] args) {
System.out.println("main running return a is "+test4());
}

运行结果:

finally running, a = xxxyyy
main running return a is xxx

有人可能又会有疑问了,String不是引用类型的对象吗?结果怎么又TM看不懂了??要知道,String虽然是引用类型的对象,但是String类有final关键字进行修饰的类(让它具有了基本数据类型的属性)。怎么理解?也就是说String是常量对象,不可更改,不同的字符串就是不同的对象。
在try中return的字符串是“xxx”,这是假设有个临时引用temp指向了“xxx”字符串。但是到了finally代码块中,a+=“yyy”,新生成了“xxxyyy”字符串,属于一个新的String对象。即try中引用a和finaly中的引用a指向的对象不是同一个了!
所以返回到main函数中的是temp指向的xxx,而在finally中输出的是a新指向的xxxyyy。

以上希望能对你们有所帮助。深入可能要设计java虚拟机的层面,我也不是很懂,这里做简单浅显的解释。