Итак, я смотрел вводный учебник по Java, и в нем говорилось, что если вы объявите ссылочный тип и еще один, равный этому объекту, если вы измените первый объект, второй тоже изменится. Например:
Point p1 = new Point(1, 1);
Point p2 = p1;
p1.x = 5;
System.out.println(p2);
и это дало бы мне вывод
java.awt.Point[x=5,y=1]
Однако я попробовал это со строкой:
String s1 = "Hello, World!";
String s2 = s1;
s1 = "Goodbye, World!";
System.out.println(s2);
но я получил
Hello, World!
как выход.
Почему это происходит, и означает ли это, что строки являются особым типом ссылочных типов, потому что они обычно используются?
Строки в Java являются неизменяемыми объектами. Они никогда не меняются. Когда вы выполняете новое задание, оно просто создает новую строку. Старый остается собрать сборщику мусора. Ваш класс Point не является неизменным объектом.
@dinosauce34: Вы не обновляете строку. Повторное присвоение нового объекта переменной ничего не делает ни со старым, ни с новым объектом. Это то же самое для String, что и для любого другого объекта.
Разница в том, что p1.x = 5;
изменяет объект, на который указывает p1
. Принимая во внимание, что s2 = s1
не изменяет объект, на который ранее указывал s2
(или объект, на который указывает s1)
.
Строка — это «специальный» объект в java. Это неизменяемый объект (фиксированный и не может быть изменен), и это будет единственный объект, который можно объявить без нового ключевого слова.
Если вы используете StringBuilder, StringBuffer, это изменяемая строка, и ваши значения будут изменены при изменении.
Когда вы копаетесь глубже, Java String приходит со многими запутанными понятиями. Когда вы используете "==", 2 разные строки с одинаковым значением возвращают одну и ту же ссылку на адрес памяти. Например.
String a1 = "abc"
String a2 = "abc"
a1 == a2 //returns true because a1 and a2 points to same reference (but not always!)
a1 == new String("abc") //returns false
/**Do use "equals", not == for string's value comparison**/
Если вы можете обдумать ссылки на объекты памяти:
String s1 = "Hello, World!"; //let's say it's allocated to memory address 0x0012
String s2 = s1; //s2 points to same memory address 0x0012
s1 = "Goodbye, World!"; //s1 points to new memory address 0x1113
System.out.println(s2) //printing value in still in memory address 0x0012
Это эквивалентно тому, что s1 указывает на новый объект, а s2 указывает на старый объект.
и когда вы вернетесь к своему примеру Point
Point p1 = new Point(1, 1);
Point p2 = p1; //p2 is referring to p1's memory address
p1.x = 5;
p1 = new Point(2,2); //Assign to new memory address, here is like the line for s1 = "Goodbye,world"
System.out.println(p2.x); //You now still get 5, because it's still old object.
Таким образом, чтобы исправить изменяемую строку, вам нужно изменить что-то вроде «Класс». «Метод», чтобы сохранить тот же изменяемый объект. Отсюда что-то вроде:
StringBuilder sb1 = new StringBuilder("Hello World");
StringBuilder sb2 = sb1; //Points to same reference address.
sb1.append("Goodbye World");
System.out.println(sb2.toString()); //Now you get Hello WorldGoodbye World.
sb1.setLength(0).append("Goodbye World"); //clear then set to new value.
System.out.println(sb2.toString()); //Now you get Goodbye World.
Итак, возвращаясь к вашему коду, s1 = "Goodbye, World!"
автоматически создает новый адрес, в то время как что-то вроде p1.x = 5
по-прежнему ссылается на старый адрес, верно?
@dinosauce34 да
@BasilBourque, о, ошибка. Поправил, спасибо.
Я работаю со многими вещами на питоне, и это та же ситуация. Возьмем, к примеру, список, в котором хранится несколько значений. Это изменится, когда вы сделаете эквивалент своего кода на python. Струны не изменятся, как вы сказали. С кодом дело в том, что объекты и классы, такие как списки, будут изменяться, потому что они не хранятся в памяти. Это просто ссылки, а не новые объекты. Когда вы переназначаете строку, назначение работает правильно, потому что это всего лишь одно значение.
Итак, просто чтобы уточнить, когда вы обновляете точечные объекты, вы изменяете исходный объект, но если вы обновляете строку, она полностью создает новую строку, поэтому
s2
по-прежнему ссылается на исходную, неизменную, верно?