Почему String неизменяема в Java?

Меня спросили в интервью, почему String неизменен

Я ответил так:

Когда мы создаем строку в java как String s1="hello";, тогда объект будет создан в пуле строк (привет) и s1 будет указывая на привет. Теперь, если снова мы сделаем String s2="hello";, тогда другой объект не будет создан, но s2 будет указывать на helloпотому что JVM сначала проверит, находится ли тот же объект в пул строк или нет. Если этого не существует, то новый создается иначе.

Теперь, если предположить, что java разрешает строку mutable, то, если мы изменим s1 на hello world, то значение s2 также будет hello world, поэтому строка java неизменна.

Может ли любой орган рассказать мне, соответствует ли мой ответ правильным или неправильным?

Ответ 1

String является неизменным по нескольким причинам, вот резюме:

  • Безопасность: параметры обычно представляются как String в сетевых подключениях, URL-адресах подключения к базе данных, именах пользователей/паролях и т.д. Если бы это было изменчиво, эти параметры можно было легко изменить.
  • Синхронизация и concurrency: создание неизменяемой String автоматически делает их потокобезопасными, тем самым устраняя проблемы синхронизации.
  • Кэширование: когда компилятор оптимизирует ваши объекты String, он видит, что если два объекта имеют одинаковое значение (a = "test" и b = "test" ) и, следовательно, вам нужен только один строковый объект (для обоих а и b эти два будут указывать на один и тот же объект).
  • Загрузка классов: String используется в качестве аргументов для загрузки классов. Если он изменен, это может привести к загрузке неправильного класса (поскольку изменяемые объекты меняют свое состояние).

При этом неизменность String означает, что вы не можете ее изменить, используя свой общедоступный API. Фактически вы можете обходить обычный API с помощью отражения. См. Ответ здесь.

В вашем примере, если String изменен, рассмотрим следующий пример:

  String a="stack";
  System.out.println(a);//prints stack
  a.setValue("overflow");
  System.out.println(a);//if mutable it would print overflow

Ответ 2

Разработчики Java решили, что Строки неизменяемы из-за следующего аспекта дизайна, эффективности и безопасности.

Строки дизайна создаются в специальной области памяти в куче java, известной как "String Intern pool". При создании новой строки (не в случае использования конструктора String() или любых других функций String, которые внутренне используют конструктор String() для создания нового объекта String; конструктор String() всегда создает новую строковую константу в пуле, если мы не будем вызовите переменную method intern()), которую он ищет в пуле, чтобы проверить, существует ли она уже. Если он существует, то верните ссылку существующего объекта String. Если String не является неизменяемым, изменение String с одной ссылкой приведет к неправильному значению для других ссылок.

Согласно этой статье о DZone:

Строка безопасности широко используется в качестве параметра для многих классов Java, например, для сетевого подключения, открытия файлов и т.д. Если String не является неизменным, соединение или файл будут изменены и могут привести к серьезной угрозе безопасности. Переменные строки могут также вызвать проблему безопасности в Reflection, поскольку параметры являются строками.

Эффективность Хэш-код строки часто используется в Java. Например, в HashMap. Будучи непреложными, гарантируется, что hashcode будет всегда одинаковым, так что он может быть кэширован, не беспокоясь об изменениях. Это означает, что нет необходимости вычислять hashcode каждый раз, когда он используется.

Ответ 3

Самая важная причина в соответствии с этой статьи о DZone:

Строковый константный пул... Если строка изменена, изменение строки с помощью одной ссылки приведет к неправильному значению для других ссылок.

Безопасность

Строка широко используется в качестве параметра для многих классов Java, например. сетевое подключение, открытие файлов и т.д. Если бы строка не была неизменной, соединение или файл были бы изменены и привели к серьезной угрозе безопасности....

Надеюсь, это поможет вам.

Ответ 4

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

1. Наличие пула констант

Как обсуждалось в статье " Почему хранилище строк в статье String Constant Pool", каждое приложение создает слишком много строковых объектов, чтобы спасти JVM от первоначального создания большого количества строковых объектов, а затем сбора мусора. JVM хранит все строковые объекты в отдельной области памяти, которая называется пулом констант String, и повторно использует объекты из этого кэшированного пула.

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

String a = "Naresh";
String b = "Naresh";
String c = "Naresh";

В приведенном выше примере строке объект со значением Naresh получит созданные в SCP только один раз, и все ссылки, a b, c будет указывать на тот же объект, но что, если мы попытаемся внести изменения в например a a.replace("a", "")

В идеале, должны иметь значение a Nresh но b, c, должен оставаться неизменным, поскольку в качестве конечного пользователя мы делаем изменения в только. a И мы знаем, что a, b, c указывают на один и тот же объект, поэтому, если мы вносим изменение в a, другие также должны отражать это изменение.

Но неизменность строки спасает нас от этого сценария, и из-за неизменности строкового объекта строковый объект Naresh никогда не изменится. Поэтому, когда мы делаем какие - либо изменения в вместо изменения в строке объект a Naresh JVM создает новый объект присвоить его, а затем внести изменения в этом объекте. a

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

И именно поэтому он обрабатывается JVM очень специально и получил специальную область памяти.

2. Поток безопасности

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

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

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

3. Безопасность

В каждом приложении нам нужно передать несколько секретов, например, имя пользователя\пароли, URL-адреса подключения и, в общем, всю эту информацию передают как строковый объект.

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

4. Класс загрузки

Как обсуждалось в Class.forName("class_name") Создание объектов с помощью Reflection в Java с примером, мы можем использовать Class.forName("class_name") для загрузки класса в память, который снова вызывает для этого другие методы. И даже JVM использует эти методы для загрузки классов.

Но если вы ясно видите, что все эти методы принимают имя класса в виде строкового объекта, поэтому строки загружаются в класс Java, а неизменяемость обеспечивает безопасность при загрузке правильного класса ClassLoader.

Предположим, что если String не был бы неизменным, и мы пытаемся загрузить java.lang.Object который был заменен на org.theft.OurObject и теперь все наши объекты имеют поведение, которое кто-то может использовать для нежелательных вещей.

5. Кэширование HashCode

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

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

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

Узнайте больше о том, почему String является неизменным и окончательным в Java.

Ответ 5

Я прочитал этот пост Почему String является неизменяемым или Final в Java и предположим, что следующая самая важная причина:

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

Ответ 6

Строка неизменна, потому что: -

1. Конструкция: - Строковый пул возможен только потому, что String неизменен в java, поэтому Java Runtime сохраняет много кучи java-памяти, потому что различные переменные String могут ссылаться на одну и ту же переменную String в бассейн. Если String не была бы неизменной, то интернирование String было бы невозможным, потому что, если бы какая-либо переменная изменила значение, она также была бы отражена и для других переменных.

2. Безопасность:. Если String не является неизменяемым, это вызовет серьезную угрозу безопасности для приложения. Например, имя пользователя базы данных, пароль передаются как String для получения соединения с базой данных, а в хост-узле программирования узлов и портовых данных передаются как String. Поскольку String неизменна, его значение не может быть изменено, иначе любой хакер может изменить ссылочное значение, чтобы вызвать проблемы с безопасностью в приложении.

3. Thread Safe:. Поскольку String неизменен, он безопасен для многопоточности, и один экземпляр String может быть разделен для разных потоков. Это позволяет избежать использования синхронизации для обеспечения безопасности потоков. Строки неявно защищены потоком.

4. classloader: - Строки используются в java classloader, а неизменяемость обеспечивает безопасность, которую загружает класс Classloader. Например, подумайте о экземпляре, в котором вы пытаетесь загрузить класс java.sql.Connection, но ссылочное значение изменено на класс myhacked.Connection, который может делать нежелательные вещи в вашей базе данных.

5. Кэширование: -. Поскольку String неизменен, его хэш-код кэшируется во время создания, и его не нужно снова вычислять. Это делает его отличным кандидатом на ключ в карте, и его обработка выполняется быстрее, чем другие ключевые объекты HashMap. Вот почему String в основном используется Object как ключи HashMap. Выше приведены некоторые из причин, о которых я мог думать, что показывает преимущества неизменности String. Его отличная особенность класса Java String и делает его особенным.

Ответ 7

Вы правы. String В java используется концепция String Pool literal. Когда создается строка и если строка уже существует в пуле, ссылка на существующую строку будет возвращена вместо создания нового объекта и возврата его ссылки. Если строка не является неизменной, изменение строки с одной ссылкой будет приводят к неправильному значению для других ссылок.

Я бы добавил еще одну вещь, так как String является неизменным, он безопасен для многопоточности, и один экземпляр String может быть разделен между различными потоками. Это позволяет избежать использования синхронизации для безопасности потоков, Строки неявно thread safe.

Ответ 8

Поскольку неизменяемые объекты не могут быть изменены, они могут свободно использоваться несколькими потоками. Это устраняет требования делать синхронизацию.

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

Ответ 9

Класс String FINAL означает, что вы не можете создать какой-либо класс, чтобы наследовать его и изменить базовую структуру и сделать Sting изменчивым.

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

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

Ответ 10

Строка задается как неизменяемая микросистемами Sun, потому что строка может использоваться для хранения в качестве ключа в коллекции карт. StringBuffer изменен. По этой причине он не может использоваться как ключ в объекте карты.

Ответ 11

Основная причина - безопасность

Многие пароли, информация о подключении db и важные параметры отправляются с использованием "String".

Ответ 12

Самая важная причина, по которой String становится неизменной в Java, - это Безопасность. Далее будет кэширование.

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

Проверьте транскрипт интервью с гослинг здесь

С стратегической точки зрения они чаще всего становятся безнадежными. И обычно есть вещи, которые вы можете сделать с неизменяемыми, которые вы не можете сделать с изменяемыми вещами, такими как кеш-результат. Если вы передадите строку методу открытия файла или передаете строку конструктору для метки в пользовательском интерфейсе, в некоторых API (например, в большинстве API Windows) вы передаете массив символов. Получателю этого объекта действительно нужно его скопировать, потому что они ничего не знают о его сроке хранения. И они не знают, что происходит с объектом, меняется ли он под их ногами.

В итоге вы почти вынуждены реплицировать объект, потому что не знаете, получаете ли вы его. И одна из приятных вещей об неизменных объектах заключается в том, что ответ: "Да, конечно, да". Потому что вопрос собственности, который имеет право изменить его, не существует.

Одной из вещей, которая вынуждала Strings быть неизменной, была безопасность. У вас есть метод открытия файла. Вы передаете ему строку. И затем он выполняет все проверки подлинности перед тем, как обойти вызов OS. Если вам удастся сделать что-то, что эффективно мутировало String, после проверки безопасности и перед вызовом ОС, тогда бум, вы находитесь. Но Strings являются неизменными, поэтому такая атака не работает. Точный пример - это то, что действительно требовало, чтобы Строки неизменяемы

Ответ 13

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

public class Main {
    public static void main(String[] args) {
        int[] a = {1, 2, 3, 4};
        int[] b = a;
        a[0] = 8;
        b[1] = 7;
        System.out.println("A: " + a[0] + ", B: " + b[0]);
        System.out.println("A: " + a[1] + ", B: " + b[1]);
        //outputs
        //A: 8, B: 8
        //A: 7, B: 7
    }
}

Мало того, что это может вызвать ошибки в коде, он также может (и будет) использоваться злоумышленником. Предположим, что у вас есть система, которая изменяет пароль администратора. Пользователь должен сначала ввести newPassword а затем oldPassword если oldPassword такой же, как adminPass программа сменит пароль adminPass = newPassword. скажем, что новый пароль имеет ту же ссылку, что и пароль администратора, поэтому плохой программист может создать temp переменную для хранения пароля администратора до того, как пользователь вводит данные, если oldPassword равно temp он изменяет пароль, иначе adminPass = temp. Кто-то, зная, что может легко ввести новый пароль и никогда не вводить старый пароль, а абракадабра имеет доступ администратора. Еще одна вещь, которую я не понимал при изучении строк, почему JVM не создает новую строку для каждого объекта и не имеет для нее уникального места в памяти, и вы можете просто сделать это с помощью new String("str"); Причина, по которой вы не хотите всегда использовать new состоит в том, что она не эффективна в памяти, и в большинстве случаев она медленнее читается больше.

Ответ 14

Если HELLO является вашей строкой, вы не можете изменить HELLO на HILLO. Это свойство называется непреложным свойством.

У вас может быть несколько указателей String, чтобы указать HELLO String.

Но если HELLO является char Array, вы можете изменить HELLO на HILLO. Например,

char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this

Ответ:

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

Ответ 15

С точки зрения Security мы можем использовать этот практический пример:

DBCursor makeConnection(String IP,String PORT,String USER,String PASS,String TABLE) {

    // if strings were mutable IP,PORT,USER,PASS can be changed by validate function
    Boolean validated = validate(IP,PORT,USER,PASS);

    // here we are not sure if IP, PORT, USER, PASS changed or not ??
    if (validated) {
         DBConnection conn = doConnection(IP,PORT,USER,PASS);
    }

    // rest of the code goes here ....
}