问题
我有一个简单的Java类,如下所示:
public class Test {
private String s;
public String foo() {
try {
s = "dev";
return s;
}
finally {
s = "override variable s";
System.out.println("Entry in finally Block");
}
}
public static void main(String[] xyz) {
Test obj = new Test();
System.out.println(obj.foo());
}
}
这段代码的输出是这样的:
Entry in finally Block
dev
为什么s
不会在56284616块中被覆盖,而是控制打印输出?
#1 热门回答(163 赞)
try
块在执行return
语句时完成,并且在return
语句执行时的值s
是该方法返回的值。 finally
clause稍后更改值434849356(在return
语句完成之后)的事实不会(在此时)更改返回值。
请注意,以上内容处理的是对finally
块中的值500032437自身的更改,而不是对s
引用的对象的更改。 Ifs
是对可变对象的引用(其中String
不是)并且在finally
块中更改了对象的内容,那么将在返回的值中看到这些更改。
所有这些操作的详细规则可以在Section 14.20.2 of the Java Language Specification找到。请注意,areturn
声明的执行计为try
块的突然终止(开始的部分"如果执行块因任何其他原因而突然完成R ...."适用)。请参阅435577609,了解为什么areturn
语句是块的突然终止。
进一步详细说明:如果由于return
语句而突然终止a62929604语句的try
块和finally
块,则适用§14.20.2的以下规则:
如果try块的执行由于任何其他原因而突然完成R [除了抛出异常],则执行finally块,然后有一个选择:如果finally块正常完成,则try语句突然完成R.如果finally块因为原因S而突然完成,则try语句突然完成,原因是S(并且原因R被丢弃)。
结果是finally
block中的return
语句确定整个try-finally
语句的返回值,并且丢弃try
block的返回值。如果try
块抛出异常,它会被acatch
块捕获,并且catch
block和finally
block都有return
语句,则类似的事情发生在try-catch-finally
语句中。
#2 热门回答(62 赞)
因为返回值在调用finally之前放在堆栈上。
#3 热门回答(33 赞)
如果我们查看字节码内部,我们会注意到JDK已经进行了重大优化,并且41222523 foo()**方法看起来像:
String tmp = null;
try {
s = "dev"
tmp = s;
s = "override variable s";
return tmp;
} catch (RuntimeException e){
s = "override variable s";
throw e;
}
和字节码:
0: ldc #7; //loading String "dev"
2: putstatic #8; //storing it to a static variable
5: getstatic #8; //loading "dev" from a static variable
8: astore_0 //storing "dev" to a temp variable
9: ldc #9; //loading String "override variable s"
11: putstatic #8; //setting a static variable
14: aload_0 //loading a temp avariable
15: areturn //returning it
16: astore_1
17: ldc #9; //loading String "override variable s"
19: putstatic #8; //setting a static variable
22: aload_1
23: athrow
java保留"dev"字符串在返回之前被更改。事实上,这里根本没有最终的阻止。