Автор: Widowmaker1984

Вопрос 8 (передача значения переменной)

"Как передается значение переменной (по ссылке/значению)?"

1. Термины семантики "pass-by-value" и семантики "pass-by-reference" относятся к параметрам функции.

1.1. Pass-by-value (передача параметра по значению). Действительный параметр (или выражение в аргументе) полностью вычисляется, и значение результата копируется в отдельную ячейку памяти, предназначенную для хранения значения этого параметра во время выполнения функции. То есть функция имеет дело с копией переменной, которую передали в функцию в качестве параметра. Место в памяти под параметр - обычно кусок runtime-стека в приложении (обрабатываемый Java), но другие языки могут выбрать хранение параметра в другом месте.

1.2. Pass-by-reference (передача параметра по ссылке). Формальный параметр действует просто как псевдоним (alias) реального параметра. Функция или метод, которая использует формальный параметр (для чтения или записи), в действительности использует актуальный параметр, существующий где-то вне функции.

скрытый текст2. Спецификация Java утверждает, что всегда передача параметров происходит по принципу pass-by-value. В Java нет такого понятия, как "pass-by-reference". Это очевидно для примитивов; в Java вообще нет такого понятия, как указатель/ссылка на примитив. Но объекты также не передаются по ссылке. Вместо этого передаются значения указателей на них. Т.е. скажем при вызове foo(d) в функцию foo передается значение указателя d, а не объект, на который он указывает. Нет никакого способа передать в качестве параметра сам объект.

2.1. То есть данные объявления идентичны:
//Java: пример объявления указателя.
Dog d;
//C++: пример объявления указателя.
Dog *d;

Используются указатели при этом тоже одинаково:
//Java: вызов метода по указателю.
d.setName("Fifi");
//C++: вызов метода по указателю.
d->setName("Fifi");

2.2. Ключевым понятием для понимания является следующее: на Java переменная myDog не является собакой, это указатель на собаку. То есть, если здесь:

Dog myDog = new Dog("Rover");
foo(myDog);

в функцию foo передается адрес созданного объекта Dog (возможно не физический адрес как таковой, но это самый простой способ правильно понимать, что происходит).

2.3. Предположим, что объект Dog находится в памяти по адресу 42. Это означает, что методу foo будет передано 42. Пусть метод foo определен так:

someDog.setName("Max"); // AAA
someDog = new Dog("Fifi"); // BBB
someDog.setName("Rowlf"); // CCC

Параметр someDog установлен в значение 42.

На строке "AAA": someDog следует за объектом Dog по указателю (который находится по адресу 42), так что для этого Dog (находящегося по адресу 42) будет запрошено изменение имени на Max.

На строке "BBB": будет создан новый объект класса Dog. Новый объект получит новый адрес в памяти. Предположим, что этот адрес 74, так что указателю someDog будет присвоено значение 74.

На строке "CCC": someDog следует за объектом Dog по указателю (который находится по адресу 74), так что для этого Dog (находящегося по адресу 74) будет запрошено изменение имени на Rowlf. После этого выполнение метода foo заканчивается.

Если иметь в виду, что myDog является указателем, а не просто объектом Dog, то вне метода foo он все еще имеет значение 42, как и до вызова функции; он все еще указывает на оригинальный объект Dog. Совершенно допустимо следовать по адресу myDog для изменения содержимого объекта, адрес myDog при этом остается однако неизменным.

Т.е. Java работает абсолютно так же, как C. Можно назначить указатель, передать указатель методу, следовать по указателю и изменять данные, на которые указатель указывает. Однако нельзя поменять место расположения объекта, на который указывает указатель.

3. Итого, Java всегда передает параметры по значению.
1

Комментарии


Лучшее   Правила сайта   Вход   Регистрация   Восстановление пароля

Материалы сайта предназначены для лиц старше 16 лет (16+)