Неизменяемость и пропуск по значению

У меня есть следующий код, который имеет измененный класс Person, String и метод для изменения экземпляров String и Person

    class Person{

int a = 8;

public int getA() {
    return a;
}

public void setA(int a) {
    this.a = a;
}

@Override
public String toString() {
    return "Person [a=" + a + "]";
}

  }

-

public class TestMutable {
public static void main(String[] args)
{
    Person p = new Person();
    p.setA(34);


    String s = "bar";

             modifyObject(s, p);   //Call to modify objects

    System.out.println(s);
    System.out.println(p);

}



private static void modifyObject(String str, Person p)
{

        str = "foo";
        p.setA(45);

}

  }

Вывод выполняется так, как ожидалось. Он печатает

           bar
          Person [a=45]

Теперь, мой вопрос:

Что происходит в месте, где вы говорите str = "foo" ?

Предположим сначала, что s = 'bar' и данные находятся в памяти 0x100

Теперь ссылка на строку передается другому методу, другой метод пытается изменить содержимое ячейки памяти (0x100) на "foo", используя s = "foo". Это то, что происходит, или "foo" создается в различной памяти?

Выполняет ли java ссылки по значению?

Ответы

Ответ 1

Java всегда передает аргументы по значению NOT по ссылке.


Позвольте мне объяснить это с помощью :

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 variable "f" 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

В modifyObject, Когда вы назначаете str, вы не мутируете str, вы устанавливаете его так, чтобы он указывал на другой объект. Поскольку он передается по значению, указатель str, локальный для вашего метода modifyObject, является копией указателя s в main, поэтому, когда вы меняете первый, это не влияет на позже.

С другой стороны, когда дело доходит до p, то в modifyObject все еще есть копия в main, но оба указателя относятся к одному и тому же объекту в памяти, следовательно, если вы вызываете метод на нем от modifyObject, вы на самом деле мутируете вещь, на которую указывает p.

Ответ 3

Иногда люди путаются при передаче по ссылке. Можно изменить объект, на который ссылается ссылка (дающее представление о прохождении ссылки), но само изменение самой ссылки невозможно. Таким образом, он по-прежнему остается пропущенным значением.

Ответ 4

В этой функции вызывается "modifyObject (s, p);" вы отправляете значение переменной s для переменной метода modObject локальной переменной str. Таким образом, создается новая переменная, и ее значение изменяется, но исходный остается неизменным.