Как реализована неизменяемость строк (String) в Java?

«Как реализована неизменяемость строк (String) в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Класс String в Java является неизменяемым (immutable) благодаря нескольким ключевым решениям в его дизайне:

  • final класс: Класс объявлен как final, что запрещает наследование и переопределение его методов.
  • private final поля: Внутренние поля (например, char[] value) объявлены как private final. Их значение можно задать только при создании объекта в конструкторе.
  • Отсутствие сеттеров: Нет публичных методов, изменяющих состояние объекта после его создания.
  • Защитное копирование: Конструкторы, принимающие изменяемые данные (например, массив char[]), создают внутреннюю копию этого массива.
  • Возврат новых объектов: Методы, которые кажутся изменяющими строку (например, concat(), substring()), на самом деле возвращают новый объект String.

Пример и последствия:

String original = "Hello";
String modified = original.concat(" World"); // Создается новый объект
System.out.println(original); // "Hello" - исходный объект не изменился
System.out.println(modified); // "Hello World"

Преимущества неизменяемости строк:

  1. Потокобезопасность: Объекты можно безопасно использовать в многопоточных сценариях без синхронизации.
  2. Кэширование хэша: Хэш-код строки вычисляется один раз и кэшируется, что повышает производительность в коллекциях вроде HashMap.
  3. Безопасность: Исключается риск непреднамеренного изменения строк, переданных в качестве параметров (например, в SecurityManager).
  4. Возможность пулинга: Механизм String Pool позволяет экономить память, повторно используя литералы и строки, созданные методом intern().