Действительно ли Java передает объекты по значению?
Возможный дубликат: Java передается по ссылке?
public class myClass{
public static void main(String[] args){
myObject obj = new myObject("myName");
changeName(obj);
System.out.print(obj.getName()); // This prints "anotherName"
}
public static void changeName(myObject obj){
obj.setName("anotherName");
}
}
Я знаю, что Java передается по значению, но почему она проходит obj
по ссылке в предыдущем примере и изменить его?
6 ответов
Java всегда передает аргументы по значению, а не по ссылке. В вашем примере вы все еще проходите obj
по своей стоимости, а не сама ссылка. Внутри вашего метода changeName
, вы назначаете другую (локальную) ссылку, obj
тому же объекту вы передали его в качестве аргумента. Как только вы измените эту ссылку, вы измените исходную ссылку, obj
, который передается в качестве аргумента.
РЕДАКТИРОВАТЬ:
Позвольте мне объяснить это на примере:
public class Main
{
public static void main(String[] args)
{
Foo f = new Foo("f");
changeReference(f); // It won't change the reference!
modifyReference(f); // It will change the object that the reference refers to!
}
public static void changeReference(Foo a)
{
Foo b = new Foo("b");
a = b;
}
public static void modifyReference(Foo c)
{
c.setAttribute("c");
}
}
Я объясню это по шагам:
1- Объявление ссылки с именем f
типа Foo
и назначить его новому объекту типа Foo
с атрибутом "f"
,
Foo f = new Foo("f");
2- со стороны метода, ссылка типа Foo
с именем a
объявлен и изначально назначен null
,
public static void changeReference(Foo a)
3- Как вы называете метод changeReference
, ссылка a
будет назначен объекту, который передается в качестве аргумента.
changeReference(f);
4- Объявление ссылки с именем b
типа Foo
и назначить его новому объекту типа Foo
с атрибутом "b"
,
Foo b = new Foo("b");
5- a = b
переназначает ссылку a
НЕ f
к объекту, чей атрибут "b"
,
6- Как вы звоните modifyReference(Foo c)
метод, ссылка c
создается и присваивается объекту с атрибутом "f"
,
7- c.setAttribute("c");
изменит атрибут объекта, на который ссылается c
указывает на это, и это тот же объект, который ссылается f
указывает на это.
Надеюсь, теперь вы понимаете, как передача объектов в качестве аргументов работает в Java:)
В Java дескриптор объекта или идентификатор объекта считается значением. Передача по значению означает передачу этого дескриптора, а не полной копии объекта.
"Ссылка" в термине "передача по ссылке" также не означает "ссылка на объект". Это означает "ссылку на переменную" - именованное "ведро" в определении функции (или, скорее, в кадре вызова), которое может хранить значение.
Передача по ссылке будет означать, что вызываемый метод может изменить значения переменных в вызывающем методе. (Например, в стандартной библиотеке C, функция scanf
работает таким образом.) Это не возможно в Java. Вы всегда можете изменить свойства объекта - они не считаются частью его "стоимости". Это совершенно разные независимые объекты.
Это не изменило obj (ваш код все равно не меняет его). Если бы он был передан по ссылке, вы могли бы написать:
public static void changeName(myObject obj){
obj = new myObject("anotherName");
}
И напечатайте "anotherName" основным методом.
Вы меняете свойство obj
, не меняется obj
(параметр) сам.
Дело в том, что если вы указали obj
на что-то еще в changeName
что это изменение не будет отражено в main
,
Смотрите этот пост для дальнейшего уточнения.
Он передает ссылку на obj в качестве значения (немного сбивающего с толку, я знаю:)).
Допустим, он создает копию указателя на значение obj и передает его.
Это означает, что вы можете делать такие вещи, как:
public static void changeName(myObject obj){
obj.setName("anotherName");
obj = new myObject();
}
и утверждение
System.out.print(obj.getName());
все еще будет ссылаться на старый объект (тот, который вы сделали setName).
Java передает копию того, что вы передаете своей функции. Когда это примитивный тип - это будет копия значения. Когда это объект - вы передаете эталонную копию. В примере кода вы изменяете одно из свойств объекта, но не саму ссылку, поэтому имя будет изменено. Однако, когда вы хотите назначить новый объект переменной obj в функции changeName, вы меняете ссылку, поэтому внешний объект obj будет иметь старое значение.