Действительно ли 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
по ссылке в предыдущем примере и меняет его?
Ответы
Ответ 1
Java всегда передает аргументы по значению, а не по ссылке. В вашем примере вы все равно передаете obj
по его значению, а не по самой ссылке. Внутри вашего метода changeName
вы назначаете другую (локальную) ссылку, obj
, тому же объекту, который вы передали в качестве аргумента. После изменения этой ссылки вы изменяете исходную ссылку, obj
, которая передается в качестве аргумента.
EDIT:
Позвольте мне объяснить это на примере:
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
NOT f
объекту, чей атрибут "b"
.
6- Как вы называете метод modifyReference(Foo c)
, создается и назначается ссылка c
объекту с атрибутом "f"
.
7- c.setAttribute("c");
изменит атрибут объекта, на который указывает ссылка c
, и на него указывает тот же объект, что и ссылка f
.
Надеюсь, теперь вы понимаете, как объекты передачи в качестве аргументов работают в Java:)
Ответ 2
В Java считается дескриптором объекта или идентификатором объекта. Передача по значению означает передачу этого дескриптора, а не полную копию объекта.
"Ссылка" в терминах "передать по ссылке" также не означает "ссылка на объект". Это означает "ссылка на переменную" - названное "ведро" в определении функции (или, скорее, кадре вызова), которое может хранить значение.
Передача по ссылке означает, что вызываемый метод может изменять значения переменных в вызывающем методе. (Например, в стандартной библиотеке C функция scanf
работает таким образом.) Это невозможно в Java. Вы всегда можете изменить свойства объекта - они не считаются частью его "значения". Это совершенно разные независимые объекты.
Ответ 3
Вы изменяете свойство obj
, не меняя obj
(самого параметра).
Дело в том, что если бы вы указали obj
на что-то еще в changeName
, что это изменение не будет отражено в main
.
См. этот пост для дальнейшего уточнения.
Ответ 4
Это не изменило obj (ваш код в любом случае не изменит его).
Если бы оно было передано по ссылке, вы могли бы написать:
public static void changeName(myObject obj){
obj = new myObject("anotherName");
}
И получите "anotherName", напечатанный основным методом.
Ответ 5
Java передает копию того, что вы передаете своей функции. Когда это примитивный тип - это будет копия значения. Когда это объект - вы передаете ссылочную копию. В примере кода вы изменяете одно из свойств объектов, но не саму ссылку, поэтому имя будет изменено. Однако, когда вы хотите назначить новый объект переменной obj в функции changeName, вы меняете ссылку, поэтому внешнее obj будет иметь старое значение.
Ответ 6
Передача ссылки на obj как значение (немного запутанная, я знаю:)).
Итак, скажем, это делает копию указателя на значение obj и передает это.
Это означает, что вы можете делать такие вещи, как:
public static void changeName(myObject obj){
obj.setName("anotherName");
obj = new myObject();
}
и утверждение
System.out.print(obj.getName());
все еще будет ссылаться на старый объект (тот, который вы установилиName).