问题 对象引用在finally块中设置为null


public void testFinally(){
System.out.println(setOne().toString());

}

protected StringBuilder setOne(){
StringBuilder builder=new StringBuilder();
try{
builder.append("Cool");
return builder.append("Return");
}finally{
builder=null; /* ;) */
}
}

为什么输出是CoolReturn,而不是null?

问候,
Mahendra Athneria


3905
2018-01-07 12:55


起源



答案:


表达式被计算为return语句中的值,这是将返回的值。执行finally块  return语句的表达式评估部分。

当然,finally块可以修改返回值引用的对象的内容 - 例如:

finally {
  builder.append(" I get the last laugh!");
}

在这种情况下,控制台输出将是“CoolReturn我笑到最后!” - 但它不能更改实际返回的值。


14
2018-01-07 12:57



@Jon,但为什么呢 builder.append("some value"); 修改实际返回值 builder = null 不? - Darin Dimitrov
@Darin:因为 builder 是一个参考。将引用设置为null会取消设置所述引用,但它引用的对象仍然存在,直到它被垃圾回收。 append另一方面,修改对象(或其中一个属性) - Powerlord
@Darin:append方法返回指向它的变量的链接。所以返回builder.append(“some value”);实际上将“some value”附加到构建器并返回到构建器的链接作为对象,您在finally块中更改。当您编写builder = null时,您只需更改构建器点的位置,而不是更改位于旧链接下的值。 - Maxym
@R。 Bemrose,@ Maxym,出色的解释。谢谢。 - Darin Dimitrov
@Darin很高兴它有帮助! - Maxym


答案:


表达式被计算为return语句中的值,这是将返回的值。执行finally块  return语句的表达式评估部分。

当然,finally块可以修改返回值引用的对象的内容 - 例如:

finally {
  builder.append(" I get the last laugh!");
}

在这种情况下,控制台输出将是“CoolReturn我笑到最后!” - 但它不能更改实际返回的值。


14
2018-01-07 12:57



@Jon,但为什么呢 builder.append("some value"); 修改实际返回值 builder = null 不? - Darin Dimitrov
@Darin:因为 builder 是一个参考。将引用设置为null会取消设置所述引用,但它引用的对象仍然存在,直到它被垃圾回收。 append另一方面,修改对象(或其中一个属性) - Powerlord
@Darin:append方法返回指向它的变量的链接。所以返回builder.append(“some value”);实际上将“some value”附加到构建器并返回到构建器的链接作为对象,您在finally块中更改。当您编写builder = null时,您只需更改构建器点的位置,而不是更改位于旧链接下的值。 - Maxym
@R。 Bemrose,@ Maxym,出色的解释。谢谢。 - Darin Dimitrov
@Darin很高兴它有帮助! - Maxym


显然它看起来应该是null但是在java中通过引用传递的概念是这样的:

1>返回 builder.append("Return")...行被执行和副本 建设者 引用返回给 testFinally() 通过引用传递的方法

2>执行时 builder=null 在 最后 阻止 建设者 引用被取消引用但是在引用的堆中的实际对象 建设者 之前仍然存在于堆中的引用和 返回的构建器引用副本 (它也是指向同一个对象的引用)仍然存在并且保持值“CoolReturn”,这就是为什么它打印返回的值。


2
2018-04-22 13:06





finally块用于“清理”,  try块的执行。当您已经返回引用时,您无法以这种方式更改它。


0
2018-01-07 12:57



我认为这有点误导 - 例如,如果finally块抛出异常,那么它仍然会被抛出。我认为将返回值的评估(在finally块之前发生)和将控制权从方法转移回调用者(在finally块之后发生)更清楚。 - Jon Skeet
你是对的,我会改变我的措辞。但无论如何你的答案是好的;-) - morja