恰好今天我的一个 “儿子” 问我一个这样的一个问题,我前段时间也刚学了JVM的一些相关知识。
我觉得这个非常的有意义,毕竟自己儿子问我这样的问题是吧!好不容易好学一次!
废话不多说,看他究竟问了我啥样的问题——————
先上代码和运行结果!!!!!
public class TryFinally {
public static void main(String[] args) {
int result = performDivision(10, 0);
System.out.println("Result: " + result);
}
public static int performDivision(int dividend, int divisor) {
int result = 0;
try {
result =4;
return result;
} catch (ArithmeticException e) {
System.out.println("Divisor cannot be zero!");
} finally {
result++;
System.out.println("This statement is always executed.");
}
//return result;
}
}
This statement is always executed.
Result: 4
他问我为什么Result返回的是4,而不是5呢?
毕竟在finally这里还有一个result++呢?
我当时很无语..........
于是给他这样解释:当执行performDivision方法时,try语句块中的代码result = 4;在执行后立即将结果4返回了,由于Java中的return语句会导致当前方法的立即退出,因此这个方法也就没有进入finally语句块的机会。然而,finally语句块中的代码result++;仍会被执行,因此result会加1。但是,因为已经返回了结果4,所以最终的打印结果只能是4。finally块中的代码总是会被执行,但是在try块中明确返回结果后,finally块的影响就不能改变已经返回的结果了。
在浏览的各位应该很容易就能知道为什么?
但是,我今天要从jvm的角度讲一下?(我不可能拿这么简单的解释来糊弄你们吧!)
拿个本本记好喽!
在JVM中,当执行try块中的return语句时,JVM会将返回值存储在一个临时寄存器中,
然后开始执行finally块中的代码。在finally块中对变量进行修改并不会改变该临时
寄存器中的值,因此finally块中对变量的修改不会影响try块中已经返回的值。
在执行finally块中的代码之后,JVM会将临时寄存器中的返回值存储到调用栈帧中
的返回值寄存器中,并将该调用栈帧出栈,将返回值传递给调用者。
因此,无论finally块中对变量进行了多少次修改,只要返回值已经在临时寄存器中被存储了,
就不会受到finally块中代码的影响,而是直接返回临时寄存器中存储的值。
因此,在这个例子中,try块中的返回值为4,已经存储在临时寄存器中
并准备被返回给调用者。虽然finally块中对变量进行了一次修改,
但是不会改变临时寄存器中的值,因此最终返回值仍为4。
也可以这样理解
在JVM的视角看,Java编译器将performDivision方法编译为字节码并在JVM中执行。
在执行try语句块时,发现其中有一个return语句,然后JVM会将这个应该返回的结果
保存在栈帧的局部变量表中,并跳转回原来的方法调用处。因为finally语句块中的
代码在执行时仅仅是对应的栈帧进行修改,并没有影响到栈顶的返回值,
所以这个方法返回的仍然是原来保存在局部变量表中的结果4。
这两个解释都大相庭径。
如果把第一个return result;注释掉,把第二个return result;作为返回值的话,那么它的结果就是5 辣!
大家懂这个JVM的编译逻辑吧。
我觉得挺好理解的!
还是不会的,可以在下方留言!
今天又学到一些小知识!真是泰裤辣!!!