Тип ссылки String в Java по сравнению с другими с точки зрения объектов

Итак, я смотрел вводный учебник по 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!

как выход.

Почему это происходит, и означает ли это, что строки являются особым типом ссылочных типов, потому что они обычно используются?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
238
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Строки в Java являются неизменяемыми объектами. Они никогда не меняются. Когда вы выполняете новое задание, оно просто создает новую строку. Старый остается собрать сборщику мусора. Ваш класс Point не является неизменным объектом.

Итак, просто чтобы уточнить, когда вы обновляете точечные объекты, вы изменяете исходный объект, но если вы обновляете строку, она полностью создает новую строку, поэтому s2 по-прежнему ссылается на исходную, неизменную, верно?

dinosauce34 13.12.2020 01:00

@dinosauce34: Вы не обновляете строку. Повторное присвоение нового объекта переменной ничего не делает ни со старым, ни с новым объектом. Это то же самое для String, что и для любого другого объекта.

Thilo 13.12.2020 03:14

Разница в том, что p1.x = 5; изменяет объект, на который указывает p1. Принимая во внимание, что s2 = s1 не изменяет объект, на который ранее указывал s2 (или объект, на который указывает s1).

Thilo 13.12.2020 03:16
Ответ принят как подходящий

Строка — это «специальный» объект в 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 13.12.2020 03:49

@dinosauce34 да

Han 15.12.2020 03:16

@BasilBourque, о, ошибка. Поправил, спасибо.

Han 15.12.2020 03:16

Я работаю со многими вещами на питоне, и это та же ситуация. Возьмем, к примеру, список, в котором хранится несколько значений. Это изменится, когда вы сделаете эквивалент своего кода на python. Струны не изменятся, как вы сказали. С кодом дело в том, что объекты и классы, такие как списки, будут изменяться, потому что они не хранятся в памяти. Это просто ссылки, а не новые объекты. Когда вы переназначаете строку, назначение работает правильно, потому что это всего лишь одно значение.

Другие вопросы по теме