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