Неизменяемость и пропуск по значению
У меня есть следующий код, который имеет
измененный класс 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");
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
В modifyObject
, Когда вы назначаете str
, вы не мутируете str
, вы устанавливаете его так, чтобы он указывал на другой объект. Поскольку он передается по значению, указатель str
, локальный для вашего метода modifyObject
, является копией указателя s
в main
, поэтому, когда вы меняете первый, это не влияет на позже.
С другой стороны, когда дело доходит до p
, то в modifyObject
все еще есть копия в main
, но оба указателя относятся к одному и тому же объекту в памяти, следовательно, если вы вызываете метод на нем от modifyObject
, вы на самом деле мутируете вещь, на которую указывает p
.
Ответ 3
Иногда люди путаются при передаче по ссылке. Можно изменить объект, на который ссылается ссылка (дающее представление о прохождении ссылки), но само изменение самой ссылки невозможно. Таким образом, он по-прежнему остается пропущенным значением.
Ответ 4
В этой функции вызывается "modifyObject (s, p);" вы отправляете значение переменной s для переменной метода modObject локальной переменной str. Таким образом, создается новая переменная, и ее значение изменяется, но исходный остается неизменным.