ссылка на объект установлена ​​в null в блоке finally

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, а не нуль?

С уважением,
Махендра Атнерия


person Mahendra Athneria    schedule 07.01.2011    source источник


Ответы (3)


Выражение оценивается как значение в операторе return, и это значение будет возвращено. Блок finally выполняется после части вычисления выражения оператора return.

Конечно, блок finally может изменить содержимое объекта, на который ссылается возвращаемое значение, например:

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

в этом случае вывод консоли будет "CoolReturn, я смеюсь последним!" - но он не может изменить значение, которое фактически возвращается.

person Jon Skeet    schedule 07.01.2011
comment
@Jon, но почему builder.append("some value"); изменяет фактическое возвращаемое значение, а builder = null нет? - person Darin Dimitrov; 07.01.2011
comment
@Darin: Потому что builder - это ссылка. Установка для ссылки значения null отменяет указанную ссылку, но объект, на который она ссылается, все еще существует до тех пор, пока он не будет удален сборщиком мусора. append, с другой стороны, изменяет объект (или одно из его свойств) - person Powerlord; 07.01.2011
comment
@Darin: метод append возвращает ссылку на переменную, для которой он был вызван. Итак, верните builder.append(некоторое значение); на самом деле добавляет какое-то значение к построителю и возвращает ссылку на построитель как объект, который вы меняете в блоке finally. Когда вы пишете builder = null, вы просто меняете, куда указывает строитель, а не значение, которое находилось под старой ссылкой. - person Maxym; 07.01.2011
comment
@Maxym - как вы сказали, написав builder = null, мы просто меняем точки строителя. я согласился. но взамен мы возвращаем ссылку, и теперь это относится к нулю. поэтому он должен использовать значение, указанное новой ссылкой. я вам понятен? - person Mahendra Athneria; 07.01.2011
comment
@Mahendra, вы оценили эту ссылку взамен ..., и вы не можете изменить ее, просто изменив указатель переменной построителя. Вы можете написать return ... в блоке finally, и тогда может быть возвращен другой объект - person Maxym; 07.01.2011
comment
@Mahendra, когда программа выполняет return ... она записывает ссылку на объект в стеке, и вы не можете изменить ее, просто изменив ссылку на построитель, потому что эта ссылка уже была оценена и помещена в стек. Может быть, так лучше объяснить - person Maxym; 07.01.2011
comment
@Maxym - вы хотите сказать, что в операторе возврата используется старая ссылка построителя, которая содержит значение CoolReturn. и в блоке finally мы модифицируем ссылку на билдер, которая неизвестна для возврата. поэтому он возвращает старое значение. но если я добавлю что-то в блок finally, например, builder.append (какое-то новое значение), то он добавит его к старому эталонному значению, то есть в CoolReturn какое-то новое значение. и он вернет CoolReturn какое-то новое значение. Отличное объяснение @Maxym. мои сомнения ясны. Благодарность :-) - person Mahendra Athneria; 07.01.2011
comment
@Mahendra не стесняйтесь спрашивать больше и не стесняйтесь исследовать и открывать для себя прекрасный мир Java;) - person Maxym; 07.01.2011

по-видимому, похоже, что он должен быть нулевым, но с концепцией передачи по ссылке в java вот как это происходит:

1> строка return builder.append("Return")... выполняется, и копия ссылки builder возвращается в метод testFinally() путем передачи по ссылке

2> При выполнении builder=null в блоке finally ссылка builder разыменовывается, но фактический объект, находящийся в куче, на который ссылается >ссылка на построитель ранее все еще присутствует в куче, а возвращенная копия ссылки на построитель (которая также является ссылкой, указывающей на тот же объект) все еще существует и который содержит значение «CoolReturn», поэтому он печатает возвращаемое значение.

person Som    schedule 22.04.2013

Блок finally используется для «очистки» после выполнения блока try. Поскольку вы уже вернули ссылку, вы не можете изменить ее таким образом.

person morja    schedule 07.01.2011
comment
Я думаю, что это немного вводит в заблуждение - например, если блок finally выдает исключение, оно все равно будет выброшено. Я думаю, что будет понятнее разделить оценку возвращаемого значения (которая происходит перед блоком finally) и передачу управления из метода обратно вызывающей стороне (которая происходит после блока finally). - person Jon Skeet; 07.01.2011
comment
Вы правы, я изменю свою формулировку. Но твой ответ в любом случае хорош ;-) - person morja; 07.01.2011