Действительно ли 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");

Enter image description here

2- Со стороны метода объявляется ссылка типа Foo с именем a и первоначально назначена на null.

public static void changeReference(Foo a)

Enter image description here

3 Как вы вызываете метод changeReference, ссылка a будет назначена объекту, который передается в качестве аргумента.

changeReference(f);

Enter image description here

4 Объявляем ссылку с именем b типа Foo и присваиваем ее новому объекту типа Foo с атрибутом "b".

Foo b = new Foo("b");

Enter image description here

5- a = b переназначает ссылку a NOT f объекту, чей атрибут "b".

Enter image description here


6- Как вы называете метод modifyReference(Foo c), создается и назначается ссылка c объекту с атрибутом "f".

Enter image description here

7- c.setAttribute("c"); изменит атрибут объекта, на который указывает ссылка c, и на него указывает тот же объект, что и ссылка f.

Enter image description here

Надеюсь, теперь вы понимаете, как объекты передачи в качестве аргументов работают в 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).