Является ли "новый String()" неизменным?

Я изучал Java String некоторое время. Следующие вопросы основаны на следующих сообщениях

Java String является специальным
Неизменяемость строки в java

  • Неизменность: Теперь, следуя неизменности, класс String был разработан так, чтобы значения в общем пуле можно было повторно использовать в других местах/переменных. Это хорошо, если String был создан как

    String a = "Hello World!";  Однако, если я создаю String как

    String b = new String("Hello World!"); почему это неизменное? (или это?). Поскольку у этого есть выделенная память кучи, я должен иметь возможность модифицировать это, не затрагивая никакой другой переменной. Итак, по дизайну, была ли какая-либо другая причина, почему String в целом считается неизменяемым? Или мое предположение неверно?

  • Во-вторых, я хотел спросить об общем пуле строк. Если я создаю строковый объект как

    String c = ""; - пустая запись, созданная в пуле?

Есть ли еще какие-либо сообщения? Если да, может ли кто-нибудь поделиться ссылкой?

Ответ 1

new String() - это выражение, которое создает String... и String является неизменным, независимо от того, как оно создается.

(Asking if [TG43] is mutable or not is nonsensical. It is program code, not a value. But I take it that that is not what you really meant.)


Если я создаю строковый объект как String c = "";, создается ли пустая запись в пуле?

Да; то есть запись создается для пустой строки. В пустом String нет ничего особенного.

(To be pedantic, the pool entry for [TG46] gets created long before your code is executed. In fact, it is created when your code is loaded ... or possibly even earlier than that.)


Итак, я хотел узнать, является ли новый объект кучи также неизменным,...

Да, это. Но неизменность является фундаментальным свойством объектов String. Все объекты String.

Видите ли, API String просто не предоставляет никаких методов для изменения String. Таким образом (кроме некоторых опасных и глупых трюков 1, использующих отражение), вы не можете изменить String.

и если да, то какова была цель?

Основной причиной того, что Java String разработан как неизменный класс, является простота. Это облегчает написание правильных программ и чтение/рассуждение о коде других людей, если базовый класс строки обеспечивает неизменный интерфейс.

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

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

Нет, это более фундаментально, чем это. Проще говоря, все объекты String неизменны. Для понимания этого не требуется никаких сложных частных рассуждений. Это просто >> is & lt; & lt;.

Для записи, если вам нужен изменчивый "строковый" объект в Java, вы можете использовать StringBuilder или StringBuffer. Но это разные типы String.


1 - The reason these tricks are (IMO) dangerous and foolish is that they affect the values of strings that are potentially shared by other parts of your application via the string pool. This can cause chaos ... in ways that the next guy maintaining your code has little chance of tracking down.

Ответ 2

Строка неизменна независимо от того, как она создается

1) Короткий ответ - да, new String() тоже неизменен.

Поскольку всякая возможная изменяемая операция (например, replace, toLowerCase etcetra), которую вы выполняете на String, не влияет на исходный экземпляр String и возвращает вам новый экземпляр.

Вы можете проверить это в Javadoc для String. Каждый public метод String, который подвергается действию, возвращает новый экземпляр String и не изменяет текущий экземпляр, на который вы вызвали метод.

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

Неизменяемость разрешена Строковый пул или кеширование

Именно из-за свойства непреложности внутренний пул строки был возможен, поскольку, когда в каком-либо другом месте требуется такое же значение String, возвращается эта неизменяемая ссылка. Если String был бы изменен, тогда было бы невозможно разделить String, как это, чтобы сохранить память.

Непревзойденность строк не была связана с пулом, но неизменность имеет больше преимуществ, связанных с ней.

Интерпретация или объединение строк - это пример шаблона проектирования Flyweight

2) Да, он будет интернирован, как и любой другой String, поскольку пустой String также является таким же String, как и другие экземпляры String.

Литература:

Ответ 3

Библиотеки Java сильно оптимизированы вокруг ограничения, что любой объект String неизменен, независимо от того, как этот объект создан. Даже если вы создаете b с помощью new, другой код, который вы передадите этому экземпляру, будет обрабатывать значение как неизменяемое. Это пример шаблона Value Object, и все преимущества (безопасность потоков, отсутствие необходимости делать частные копии) применяются.

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

Ответ 4

1) Неизменяемая часть не из-за пула; это просто делает пул возможным в первую очередь. Строки часто передаются в качестве аргументов для других функций или даже совместно с другими потоками; Создание неизменяемых строк было конструктивным решением облегчить рассуждения в таких ситуациях. Итак, да - String в Java всегда неизменны, независимо от того, как вы их создаете (обратите внимание, что в java возможно иметь изменяемые строки в java - просто не с классом String).

2) Да. Вероятно. Я на самом деле не уверен на 100%, но это должно быть так.

Ответ 5

Из Документация Java Oracle:

Строки постоянны; их значения не могут быть изменены после того, как они создано.

И снова:

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

Вообще говоря: "все примитивные" (или связанные) объекты неизменны (пожалуйста, примите мое отсутствие формализма).

Связанная запись в Stack Overflow:

О пуле объектов: пул объектов - это оптимизация java, которая НЕ относится к неизменяемым.

Ответ 6

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

После того, как вы построили свою строку таким образом, чтобы вы ее довольствовались, вы просто вызываете toString() на ней, чтобы преобразовать ее в обычный String, который вы можете передать библиотечным программам и другим функции, которые принимают только String s.

Кроме того, как StringBuilder, так и String реализует интерфейс CharSequence, поэтому, если вы хотите записывать функции в свой собственный код, который может использовать как изменяемые, так и неизменяемые строки, вы можете объявить их для принятия любого CharSequence объект.

Ответ 7

Строка неизменна, означает, что вы не можете изменить сам объект независимо от того, как вы его создали. И что касается второго вопроса: да, он создаст запись.

Ответ 8

На самом деле это наоборот.

[...] класс String был спроектирован так, чтобы значения в общем пуле можно было повторно использовать в других местах/переменных.

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

Итак, рассмотрим следующее:

// this string literal is interned and referenced by 'a'
String a = "Hello World!";

// creates a new instance by copying characters from 'a'
String b = new String(a);

Теперь, что произойдет, если вы просто создадите ссылку на новую созданную переменную b?

// 'c' now points to the same instance as 'b'
String c = b;

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

Почему это так?

Если ничего другого, это потому, что неизменные объекты делают многопоточность намного проще и обычно быстрее. Если вы передаете изменяемый объект (который будет представлять собой любой объект с состоянием, с изменяемыми частными/общедоступными полями или свойствами) между различными потоками, вам необходимо проявлять особую осторожность, чтобы обеспечить синхронизированный доступ (мьютексы, семафоры). Даже при этом вам нужна особая осторожность, чтобы обеспечить атомарность во всех ваших операциях. Многопоточность жесткая.

Что касается последствий для производительности, обратите внимание, что довольно часто копирование всей строки в новый экземпляр, чтобы изменить даже один символ, на самом деле быстрее, чем вызывать дорогостоящий переключатель контекста из-за конструкций синхронизации, необходимых для обеспечения потокобезопасного доступа, И, как вы уже упоминали, неизменяемость также предлагает возможности интернирования, а это означает, что это может помочь уменьшить использование памяти.

Как правило, довольно хорошая идея сделать так много неизменного, как ваша возможность.

Ответ 9

1) Неизменяемость: Строка будет неизменной, если вы создадите ее с помощью нового или другого способа по соображениям безопасности.

2) Да, в пуле строк будет пустая запись.

Вы можете лучше понять концепцию, используя код

    String s1 = new String("Test");
    String s2 = new String("Test");
    String s3 = "Test";
    String s4 = "Test";

    System.out.println(s1==s2);//false
    System.out.println(s1==s3);//false
    System.out.println(s2==s3);//false
    System.out.println(s4==s3);//true

Надеюсь, это поможет вашему запросу. Вы всегда можете проверить исходный код для класса String в случае лучшего понимания. Ссылка: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java

Ответ 11

Созданные строки всегда будут неизменными независимо от того, как они создаются.

Ответы на ваши вопросы:

  • Единственное отличие:
    Когда строка создается как - {String a = "Hello World!";}, тогда создается только один объект.
    И когда он создается как - {String b = new String("Hello World!");}, тогда создаются два объекта. Первый, потому что вы использовали ключевое слово 'новое', а второе - свойство Строка.

  • Да, конечно. В пуле будет создана пустая запись.

Ответ 12

Строка неизменна, потому что она не дает вам возможность изменить ее. Это дизайн, чтобы избежать каких-либо подделок (он окончательный, основной массив не должен быть затронут...).

Точно так же Integer неизменен, потому что нет возможности его модифицировать.

Неважно, как вы его создаете.

Ответ 13

Неизменность не является особенностью new, это особенность класса String. Он не имеет методов мутаторов, поэтому он неизменен.

Ответ 14

 String A = "Test"
 String B = "Test"

Теперь String B called "Test".toUpperCase() which change the same object into "TEST" , so A will also be "TEST" `, что нежелательно.

Ответ 15

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

Вы можете изменить строку с помощью b=b+"x"; или b=new String(b);, и содержимое переменной a похоже изменится, но не путайте неизменность ссылки (здесь переменная b), а объект ссылаясь на (думайте о указателях в C). Объект, на который ссылается ссылка, останется неизменным после его создания.

Если вам нужно изменить строку, изменив содержимое объекта (вместо изменения ссылки), вы можете использовать StringBuffer, который является изменяемой версией String.