Вопрос 4 · Раздел 13

Почему класс String является иммутабельным?

Класс String в Java нельзя изменить после создания. Любая операция, которая "меняет" строку, на самом деле создаёт новую строку.

Версии по языкам: English Russian Ukrainian

Junior Level

Класс String в Java нельзя изменить после создания. Любая операция, которая “меняет” строку, на самом деле создаёт новую строку.

String s = "Hello";
s.concat(" World"); // s всё ещё "Hello", результат нужно присвоить
s = s.concat(" World"); // теперь s = "Hello World" (новый объект)

Почему так сделали?

  1. Безопасность — строки используются для путей к файлам, URL, подключений к БД
  2. Потокобезопасность — строки можно передавать между потоками без проблем
  3. Экономия памяти — одинаковые строки переиспользуются (String Pool)

Обратная сторона: хранение паролей в String — плохая практика (см. файл 5).


Middle Level

String Pool

При создании строки-литерала JVM проверяет, есть ли уже такая строка в пуле. Если есть — возвращает ссылку на неё, если нет — создаёт новую:

String a = "Hello";
String b = "Hello";
System.out.println(a == b); // true — одна и та же ссылка из пула

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

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

Стабильность hashCode

String кэширует свой hashCode() при первом вычислении. Это делает строки идеальными ключами для HashMap:

Map<String, Integer> map = new HashMap<>();
map.put("key", 42); // hashCode вычислен один раз
map.get("key");     // используется тот же hashCode

Как это реализовано в JDK

  • Класс помечен как final (запрет наследования)
  • Внутреннее поле byte[] value (Java 9+) или char[] (старые версии) — private final
  • Нет методов, модифицирующих это поле

Senior Level

Архитектурное значение

Иммутабельность String — это не просто удобство, а фундаментальный architectural decision, на котором базируются:

  1. String Pool (Flyweight паттерн) — без иммутабельности пул невозможен: изменение строки в одном месте сломает все ссылки на неё
  2. Security Manager — проверки доступа к файлам, сетям, классам основаны на неизменяемости строк-параметров
  3. Class Loading — имена классов и путей загрузки неизменяемы, что предотвращает подмену классов
  4. HashMap стабильность — кэшированный hashCode гарантирует корректную работу хеш-таблиц

Эволюция реализации

  • Java 8 и раньше: private final char[] value — каждый символ 2 байта (UTF-16)
  • Java 9+: private final byte[] value + поле coder — Compact Strings (Latin-1 = 1 байт, UTF-16 = 2 байта) // Замена char[] на byte[] (Java 9+, Compact Strings) экономит ~50% памяти для строк с латинскими символами.

Резюме для Senior

  • Иммутабельность String — фундамент для String Pool, Security и Thread Safety
  • Позволяет JVM оптимизировать работу с памятью и кэшировать хеш-коды
  • Любое “изменение” строки порождает новый объект в куче
  • Без иммутабельности String вся платформа Java была бы уязвимой. Пример TOCTOU-атаки: проверяется путь /safe/path, но затем строка меняется на /etc/passwd.

🎯 Шпаргалка для интервью

Обязательно знать:

  • String — final класс, приватное поле byte[] value, нет методов модификации
  • String Pool — одинаковые строки переиспользуются, работает ТОЛЬКО благодаря иммутабельности
  • Безопасность — строки используются для путей к файлам, URL, подключений к БД
  • Стабильность hashCode — String кэширует hashCode, идеален как ключ HashMap
  • Эволюция: Java 8 char[] (2 байта/символ) → Java 9+ byte[] + coder (Compact Strings, 1 байт для Latin-1)
  • Без иммутабельности String вся платформа Java уязвима (TOCTOU-атаки)

Частые уточняющие вопросы:

  • Почему String final? — Чтобы подкласс не добавил мутабельность и не переопределил hashCode/equals
  • Что такое Compact Strings? — Java 9+: латинские символы хранятся в 1 байте вместо 2
  • Почему String кэширует hashCode? — Вычисляется один раз, ускоряет работу в HashMap
  • Что было бы без иммутабельности String? — String Pool невозможен, Security Manager обойдён

Красные флаги (НЕ говорить):

  • «String можно менять через concat» — concat создаёт НОВУЮ строку, оригинал не меняется
  • «String Pool в PermGen» — с Java 7+ пул переехал в Heap
  • «Иммутабельность String — только удобство» — это фундаментальный architectural decision
  • «byte[] значит String mutable» — поле private final, доступа извне нет

Связанные темы:

  • [[5. Какие последствия иммутабельности String]]
  • [[18. Как работает String pool и как это связано с иммутабельностью]]
  • [[19. Можно ли изменить значение String через рефлексию]]
  • [[27. Можно ли использовать иммутабельные объекты как ключи в HashMap]]