Техотдел
Свет ученья
Гадание на кофейной гуще, или передача по значению в Java | Гадание на кофейной гуще, или передача по значению в Java - Гадание на кофейной гуще... |
|
|
Страница 1 из 3 Sunday, 12 March 2006 | Андрей Озеров , cайт Javable.com для раздела Ученье – свет (Примечание редактора колонки Андрея Терешко, далее — прим. редактора: Не стоит гадать на кофейной гуще, надо больше пить кофе — этот прелестный напиток. ;-) )Однажды, придя в очередной раз на техническое интервью для устройства на работу в одну IT — компанию, с целью проверки моих скромных познаний основ языка Java, меня спросили: “Как происходит передача объектов в методы в качестве параметров?”.
Данный вопрос не застал меня врасплох, и я с гордостью ответил: “Передача примитивов в методы в качестве параметров происходит по значению, а объектов – по ссылке”. Данный ответ вполне удовлетворил моего будущего коллегу, и после непродолжительной беседы я был принят в компанию в качестве разработчика программного обеспечения. (прим. редактора: если бы спрашивающий более досконально разбирался в программировании на Java, то автора статьи не приняли бы на работу и … пропал бы программист для Java. ;-) ).
Однако спустя некоторое время я все больше и больше стал задумываться над проблемой передачи и возвращении объектов в/из методов. На мои размышления огромное влияние оказала книга Брюса Эккеля, где он подробно описывает поведение объекта при передаче ссылки на него в качестве параметра методу. Да, я не оговорился, действительно передача объекта в метод происходит путем передачи ссылки на этот объект. (прим. редактора: точнее - передача методу в качестве параметра переменной некоторого типа. Тип может быть "примитивным" — это boolean, char, int и т.д. и "объектным" — это то, что не относится к примитивному типу. В случае объектного типа методу в качестве параметра действительно передается ссылка на объект — не передавать же весь объект в метод? Но, что же это за ссылка передается?). Тогда возьмем для примера простую программку и посмотрим, измениться ли объект, если в методе переопределить эту ссылку. (прим. редактора: более точно, данный пример проверяет, окажет ли какое либо влияние в вызывающем методе изменение, совершенное в вызванном методе и заключающееся в изменении значения ссылки на параметр объектного типа, переданный методу).
public class HelloWorld {
static void changeIt(String value) {
value = new
String("Hello!");
}
public static void main(String[] argvc)
{
String test = new String("Hello
World!");
changeIt(test);
System.out.println("After changing : " +
test);
}
}
Результат выполнения программы из Листинга 1 немного удивил меня. Объект test в методе main не изменил своего состояния после вызова статического метода класса — changeIt. (прим. редактора: если бы это произошло, то это было бы печально.) Следовательно, в данном случае здесь происходит какое-то дополнительное действие, которое я упустил.
Самое время обратиться к первоисточникам, вот что по этому поводу сказано в спецификации самого языка: “Method parameters (§8.4.1) name argument values passed to a method. For every parameter declared in a method declaration, a new parameter variable is created each time that method is invoked (§15.12). The new variable is initialized with the corresponding argument value from the method invocation. The method parameter effectively ceases to exist when the execution of the body of the method is complete.” Иными словами для каждого параметра метода создается своя локальная копия. Следовательно, в Java методах все аргументы передаются по значению. В случае, когда аргумент – примитивный тип, передача по значению означает то, что метод не может изменить оригинальное значение. Когда же аргумент – ссылка на объект, создается локальная копия ссылки, которая указывает на тот же самый объект, при изменении которой оригинальное состояние объекта остается неизменным. (прим. редактора: верно - ВСЕ ПАРАМЕТРЫ В JAVA ПЕРЕДАЮТСЯ ПО ЗНАЧЕНИЮ. Если параметр — ссылка на объект, то ЗНАЧЕНИЕМ является ЗНАЧЕНИЕ самой ссылки, а не значение разнообразных полей в объекте, коих может быть великое множество, как по количеству, так и по разнообразию типов).
Теперь все становиться на свои места. В случае программы из Листинга 1. мы передали ссылку на объект типа String в метод, где создалась временная копия этой ссылки. (прим. редактора: точнее, сначала была создана копия ссылки (временная или нет — это отдельный разговор. Возможно, эта копия "переживет" и свой оригинал, ведь вызванный метод объекта может сохранить эту копию в поле своего или чужого объекта), а затем эта копия ссылки и была передана вызванному методу. То есть, в памяти уже содержатся две ссылки, содержащие одно и тоже значение! И если бы в вызванном методе был вызван еще другой метод с передачей ему параметра в виде ссылки на тот же объект, то в памяти находилось бы уже три ссылки, содержащих одно и тоже значение! И т.д.) Затем мы переопределили ссылку внутри метода, теперь она указывает на другой объект, но по возвращении из метода мы продолжаем работать с оригинальной ссылкой test, которая осталась неизменной.
|
|||||