return 语句对应两条汇编指令:
- 将返回值写入到某个寄存器中
- 执行 ret 指令返回到调用函数的位置。
在 Java 中,在这两个指令之间可以插入很多其他的指令,比如 finally 代码块中的指令。对于有 finally 语句的代码,执行到 return 语句时,先将返回值放入到返回值寄存器中,然后继续执行 finally 代码块中的指令。理解了这一点就非常容易理解下面这些代码的执行顺序:
public static int getInt() {
int a = 10;
try {
return a;
} finally {
a = 40;
}
}
输出: 10
执行到 try 代码块中的 return a 语句时,先将 a 的值,也就是 10 放入到返回值寄存器中,然后执行 finally 代码块中内容。由于 finally 代码块中的指令并没有修改返回值寄存器里面的内容,所以寄存器里面的值还是 10。所以 getInt() 的返回值是 10。
再看一段在 finally 中修改返回值代码:
public static int getInt() {
int a = 10;
try {
return a;
} finally {
a = 40;
return a;
}
}
输出: 40
根据我们上面的分析: try 代码块中的 return a 先将 a 的值,也就是 10 放入到返回值寄存器中,然后执行 finally 代码块中的内容,由于 finally 代码块中也有 return 语句,所以将 a 的值,也就是 40 放入到寄存器中,因此 getInt() 的返回值是 40。
再看下面的这段代码,返回值是多少呢?
public static int getInt() {
int a = 10;
try {
System.out.println(a / 0);
return a;
} catch (ArithmeticException e) {
a = 30;
return a;
} finally {
a = 40;
}
}
输出: 30
要理解为什么输出是 30, 就得知道 try, catch 和 fianlly 代码块的执行顺序了。只需要记住一点即可: fianlly 里面的语句永远是最后执行的。
由于 try 中发生异常,所以执行 catch 代码块中代码,执行到 return a; 语句时,将 a 的值也就是 30 放入到返回值寄存器中,因为有 finally 代码块,所以执行 finally 代码块中的语句,由于 finally 代码块中并没有 return 语句,所以返回值寄存器里面的内容没有发生变化,还是 30, 所以 getInt() 的返回值是 30。
再看一段在 finally 中修改返回值代码:
public static int getInt() {
int a = 10;
try {
System.out.println(a / 0);
return a;
} catch (ArithmeticException e) {
a = 30;
return a;
} finally {
a = 40;
return a;
}
}
输出: 40
这段代码就不解释了。
总结
return语句对应两条汇编指令: 将返回值放入到返回值寄存器中 + 返回到调用函数的地方- 在
return两条汇编指令之间可以插入fianlly代码块中的指令。 - 在执行
finally代码块中的指令之前,会先执行return的第一条汇编指令: 将返回值写入到返回值寄存器中 finally其实是语法糖,让代码更为的简洁,避免代码冗余。如果没有fianlly语法糖,就需要将finally代码块中的指令在try和catch中都放一份。