Вопрос-ответ

Immutability of Strings in Java

Неизменяемость строк в Java

Рассмотрим следующий пример.

String str = new String();

str = "Hello";
System.out.println(str); //Prints Hello

str = "Help!";
System.out.println(str); //Prints Help!

Теперь, в Java, строки неизменяемы. Тогда почему объекту str может быть присвоено другое значение, например "Help!". Не противоречит ли это неизменяемости строк в Java? Кто-нибудь, пожалуйста, может объяснить мне точную концепцию неизменяемости?

Редактировать:

ОК. Теперь я понял, но только один последующий вопрос. Как насчет следующего кода:

String str = "Mississippi"; 
System.out.println(str); // prints Mississippi

str = str.replace("i", "!");
System.out.println(str); // prints M!ss!ss!pp!

Означает ли это, что два объекта создаются снова ("Mississippi" и "M!ss!ss!pp!"), а ссылка str указывает на другой объект после replace() метода?

Переведено автоматически
Ответ 1

str это не объект, это ссылка на объект. "Hello" и "Help!" это два разных String объекта. Таким образом, str указывает на строку. Вы можете изменить то, на что оно указывает, но не то, на что оно указывает.

Возьмем, к примеру, этот код:

String s1 = "Hello";
String s2 = s1;
// s1 and s2 now point at the same string - "Hello"

Теперь нет ничего, что 1 мы могли бы сделать с s1, что повлияло бы на значение s2. Они ссылаются на один и тот же объект - строку "Hello" - но этот объект неизменяем и, следовательно, не может быть изменен.

Если мы сделаем что-то вроде этого:

s1 = "Help!";
System.out.println(s2); // still prints "Hello"

Здесь мы видим разницу между изменением объекта и изменением ссылки. s2 по-прежнему указывает на тот же объект, на который мы изначально указалиs1. Установка s1 в "Help!" значение изменяет только ссылку, в то время как String объект, на который она первоначально ссылалась, остается неизменным.

Если бы строки были изменяемыми, мы могли бы сделать что-то вроде этого:

String s1 = "Hello";
String s2 = s1;
s1.setCharAt(1, 'a'); // Fictional method that sets character at a given pos in string
System.out.println(s2); // Prints "Hallo"

Отредактируйте, чтобы ответить на правку OP:

Если вы посмотрите на исходный код String.replace(char,символ) (также доступен в src.zip в вашем каталоге установки JDK ( профессиональный совет - заглядывать туда всякий раз, когда вам интересно, как что-то действительно работает) вы можете увидеть, что это делает следующее:


  • Если в текущей строке есть одно или несколько вхождений oldChar, создайте копию текущей строки, в которой все вхождения oldChar заменяются на newChar.

  • Если oldChar отсутствует в текущей строке, верните текущую строку.

Итак, да, "Mississippi".replace('i', '!') создает новый String объект. Опять же, выполняется следующее:

String s1 = "Mississippi";
String s2 = s1;
s1 = s1.replace('i', '!');
System.out.println(s1); // Prints "M!ss!ss!pp!"
System.out.println(s2); // Prints "Mississippi"
System.out.println(s1 == s2); // Prints "false" as s1 and s2 are two different objects

Ваше домашнее задание на данный момент - посмотреть, что сделает приведенный выше код, если вы измените s1 = s1.replace('i', '!'); на s1 = s1.replace('Q', '!'); :)


1 На самом деле, есть возможность изменять строки (и другие неизменяемые объекты). Это требует осмысления и очень, очень опасно, и его никогда не следует использовать, если вы действительно не заинтересованы в уничтожении программы.

Ответ 2

Объект, на который str ссылаются, может изменяться, но сами фактические String объекты изменяться не могут.

String Объекты, содержащие строку "Hello" и "Help!", не могут изменять свои значения, следовательно, они неизменяемы.

Неизменяемость String объектов не означает, что ссылки, указывающие на объект, не могут изменяться.

Один из способов предотвратить изменение str ссылки - объявить ее как final:

final String STR = "Hello";

Теперь попытка присвоить другое String значение STR вызовет ошибку компиляции.

Ответ 3

Light_handle Я рекомендую вам ознакомиться с Cup Size - рассказом о переменных и передаче по значению, пожалуйста (Размер чашки продолжается). Это очень поможет при чтении сообщений выше.

Вы их читали? ДА. Хорошо.

String str = new String();

Это создает новый "удаленный элемент управления" с именем "str" и присваивает ему значение new String() (или "").

например, в памяти это создает:

str --- > ""

str  = "Hello";

Затем это изменяет удаленный элемент управления "str", но не изменяет исходную строку "".

например, в памяти это создает:

str -+   ""
+-> "Hello"

str = "Help!";

Затем это изменяет удаленный элемент управления "str", но не изменяет исходную строку "" или объект, на который в данный момент указывает удаленный элемент управления.

например, в памяти это создает:

str -+   ""
| "Hello"
+-> "Help!"
Ответ 4

Давайте разберем это на несколько частей

String s1 = "hello";

Этот оператор создает строку, содержащую hello, и занимает место в памяти, т.е. в пуле постоянных строк, и присваивает ее объекту-ссылке s1

String s2 = s1;

Этот оператор присваивает ту же строку hello новой ссылке s2

         __________
| |
s1 ---->| hello |<----- s2
|__________|

Обе ссылки указывают на одну и ту же строку, поэтому выведите одно и то же значение следующим образом.

out.println(s1);    // o/p: hello
out.println(s2); // o/p: hello

Хотя строка неизменяема, присвоение может быть возможным, поэтому s1 теперь будет ссылаться на новое значение stack.

s1 = "stack";    
__________
| |
s1 ---->| stack |
|__________|

Но как насчет объекта s2, который указывает на hello, все будет как есть.

         __________
| |
s2 ---->| hello |
|__________|

out.println(s1); // o/p: stack
out.println(s2); // o/p: hello

Поскольку строка неизменяема, виртуальная машина Java не позволит нам изменять строку s1 своим методом. Она создаст все новые объекты String в пуле следующим образом.

s1.concat(" overflow");

___________________
| |
s1.concat ----> | stack overflow |
|___________________|

out.println(s1); // o/p: stack
out.println(s2); // o/p: hello
out.println(s1.concat); // o/p: stack overflow

Примечание, если строка была бы изменяемой, то результат был бы

out.println(s1);    // o/p: stack overflow

Теперь вы можете быть удивлены, почему для изменения String используются такие методы, как concat() . Следующий фрагмент прояснит ваше замешательство.

s1 = s1.concat(" overflow");

Здесь мы присваиваем измененное значение string обратно ссылке s1.

         ___________________
| |
s1 ---->| stack overflow |
|___________________|


out.println(s1); // o/p: stack overflow
out.println(s2); // o/p: hello

Вот почему Java решила, что String будет конечным классом В противном случае любой может модифицировать и изменять значение string .
Надеюсь, это немного поможет.

java string