java - это - почему string immutable c#




Строка неизменна. В чем же смысл? (13)

На этот вопрос уже есть ответ:

Я написал следующий код на неизменяемых строках.

public class ImmutableStrings {

    public static void main(String[] args) {
        testmethod();
    }

    private static void testmethod() {
        String a = "a";
        System.out.println("a 1-->" + a);
        a = "ty";
        System.out.println("a 2-->" + a);
    }
}

Вывод:

a 1-->a  
a 2-->ty

Здесь значение переменной a было изменено (в то время как многие говорят, что содержимое неизменяемых объектов не может быть изменено). Но что именно означает, что String является неизменным ? Не могли бы вы прояснить эту тему для меня?

источник: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html


В вашем примере a сначала ссылается на "a" , а затем на "ty" . Вы не мутируете какой-либо экземпляр String ; вы просто изменяете, к чему относится экземпляр String . Например, это:

String a = "a";
String b = a; // b refers to the same String as a
a = "b"; // a now refers to a different instance
System.out.println(b);

печатает «a», потому что мы никогда не мутируем экземпляр String который указывает b .


В вашем примере переменная a является просто ссылкой на экземпляр строкового объекта. Когда вы говорите a = "ty" , вы фактически не изменяете строковый объект, а скорее указываете ссылку на совершенно другой экземпляр класса string.


Вы меняете то, a что ссылаетесь . Попробуй это:

String a="a";
System.out.println("a 1-->"+a);
String b=a;
a="ty";
System.out.println("a 2-->"+a);
System.out.println("b  -->"+b);

Вы увидите, что объект, к которому относится a а затем b , не изменился.

Если вы хотите, чтобы ваш код не изменял объект, a ссылается объект, попробуйте:

final String a="a";

Вы не изменяете объект в инструкции присваивания, вы заменяете один неизменяемый объект на другой. String("a") объекта String("a") не изменяется на String("ty") , она отбрасывается, а ссылка на ty записывается в нее вместо нее.

Напротив, StringBuffer представляет собой изменяемый объект. Вы можете сделать это:

StringBuffer b = new StringBuffer("Hello");
System.out.writeln(b);
b.append(", world!");
System.out.writeln(b);

Здесь вы не повторно назначили b : он все еще указывает на тот же объект, но содержимое этого объекта изменилось.


Изменяется только эта ссылка. Сначала a ссылался на строку «a», а позже вы изменили ее на «ty». Строка «a» остается неизменной.


Надеюсь, что приведенный ниже код прояснит ваши сомнения:

public static void testString() {
    String str = "Hello";
    System.out.println("Before String Concat: "+str);
    str.concat("World");
    System.out.println("After String Concat: "+str);
    StringBuffer sb = new StringBuffer("Hello");
    System.out.println("Before StringBuffer Append: "+sb);
    sb.append("World");
    System.out.println("After StringBuffer Append: "+sb);
}

Перед String Concat: Привет
После String Concat: Hello
Перед добавлением StringBuffer: Hello
После добавления StringBuffer: HelloWorld


Прежде чем приступить к дальнейшей суете незыблемости , давайте просто взглянем на класс String и его функциональные возможности, прежде чем прийти к какому-либо выводу.

Вот как работает String :

String str = "knowledge";

Это, как обычно, создает строку, содержащую "knowledge" и присваивает ей ссылку str . Достаточно просто? Позволяет выполнить еще несколько функций:

 String s = str;     // assigns a new reference to the same string "knowledge"

Давайте посмотрим, как работает следующее выражение:

  str = str.concat(" base");

Это добавляет строку " base" к str . Но подождите, как это возможно, поскольку объекты String неизменяемы? Ну, к вашему удивлению, это так.

Когда выполняется вышеуказанный оператор, VM берет значение String str , то есть "knowledge" и добавляет " base" , предоставляя нам значение "knowledge base" . Теперь, поскольку String s неизменяемы, VM не может присвоить это значение str , поэтому он создает новый объект String , дает ему значение "knowledge base" и дает ему ссылку str .

Здесь важно отметить, что, хотя объект String неизменен, его ссылочной переменной нет. Вот почему в приведенном выше примере ссылка ссылалась на вновь образованный объект String .

На этом этапе в приведенном выше примере у нас есть два объекта String : первый, который мы создали со значением "knowledge" , на которое указывает s , и вторая "knowledge base" , на которую указывает str . Но, технически, у нас есть три объекта String , третий - буквальная "base" в выражении concat .

Важные факты о использовании строк и памяти

Что, если бы у нас не было другой ссылки на "knowledge" ? Мы бы потеряли эту String . Однако он все еще существовал бы, но считался бы утраченным из-за отсутствия ссылок. Посмотрите еще один пример ниже

String s1 = "java";
s1.concat(" rules");
System.out.println("s1 refers to "+s1);  // Yes, s1 still refers to "java"

Что происходит:

  1. Первая строка довольно проста: создайте новую String "java" и обратитесь к ней s1 .
  2. Затем VM создает еще один новый "java rules" String , но ничто не ссылается на него. Итак, вторая String мгновенно теряется. Мы не можем достичь этого.

Контрольная переменная s1 прежнему относится к исходной String "java" .

Почти каждый метод, применяемый к объекту String для его модификации, создает новый объект String . Итак, куда идут эти объекты String ? Ну, они существуют в памяти, и одной из ключевых целей любого языка программирования является эффективное использование памяти.

Поскольку приложения растут, для String литералов очень часто занимать большую площадь памяти, что может даже вызвать избыточность. Итак, чтобы сделать Java более эффективной, JVM выделяет специальную область памяти, называемую «String constant pool».

Когда компилятор видит String литерал, он ищет String в пуле. Если совпадение найдено, ссылка на новый литерал направлена ​​на существующую String и новый объект String не создается. Существующая String просто имеет еще одну ссылку. Здесь возникает смысл сделать объекты String неизменяемыми:

В пуле констант String объект String может иметь одну или несколько ссылок. Если несколько ссылок указывают на ту же String даже не зная ее, было бы плохо, если бы одна из ссылок изменила значение String . Вот почему объекты String неизменяемы.

Итак, теперь вы можете сказать, что, если кто-то переопределит функциональность класса String ? Вот почему класс String помечен как final так что никто не может переопределить поведение его методов.


Строка - это char[] содержащая ряд кодовых единиц UTF-16 , смещение int в этот массив и длину int .

Например.

String s

Он создает пространство для ссылки на строку. Назначение ссылок на копии, но не изменяет объекты, к которым относятся эти ссылки.

Вы также должны знать, что

new String(s)

не делает ничего полезного. Он просто создает другой экземпляр, поддерживаемый тем же массивом, смещением и длиной, что и s . Для этого очень редко возникает причина, поэтому большинство программистов Java считают это плохой практикой.

Строки с двойными кавычками Java, такие как "my string" , действительно являются ссылками на interned экземпляры String поэтому "bar" является ссылкой на тот же экземпляр String, независимо от того, сколько раз он появляется в вашем коде.

«Привет» создает один экземпляр, который объединяется, а new String(...) создает экземпляр без объединения. Попробуйте System.out.println(("hello" == "hello") + "," + (new String("hello") == "hello") + "," + (new String("hello") == new String("hello"))); и вы должны увидеть true,false,false


Строка неизменной означает, что содержимое объекта String нельзя изменить

если вы хотите изменить содержимое, используйте StringBuffer вместо String, который изменен



глянь сюда

class ImmutableStrings {

    public static void main(String[] args) {
        testmethod();
    }

    private static void testmethod() {
    String a="a";
    System.out.println("a 1-->"+a);
    System.out.println("a 1 address-->"+a.hashCode());

    a = "ty";
    System.out.println("a 2-->"+a);

       System.out.println("a 2 address-->"+a.hashCode());
    }
}

вывод:

a 1-->a
a 1 address-->97
a 2-->ty
a 2 address-->3717

Это означает, что всякий раз, когда вы изменяете содержимое неизменяемого строкового объекта, a создан новый объект. т.е. вам не разрешено изменять содержимое неизменяемого объекта. поэтому адрес для обоих объектов отличается.


неизменяемое означает, что вы не можете изменить значение одного и того же реферала. Каждый раз, когда вы должны создавать новые ссылки, это означает новое местоположение памяти. например:

String str="abc";
str="bcd";

здесь, в приведенном выше коде, в памяти есть 2 блока для хранения значения. Первый для значения «abc» и второй для «bcd». Второе значение не заменяет первое значение.

это называется непреложным.


String S1="abc";
S1.concat("xyz");
System.out.println("S1 is", + S1);
String S2=S1.concat("def");
System.out.println("S2 is", + S2);

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





immutability