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

Как работает String pool и как это связано с иммутабельностью?

Если бы строки можно было менять, то изменение одной строки повлияло бы на все остальные, которые ссылаются на неё:

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

Junior Level

String Pool — это специальное хранилище в памяти, где Java хранит только одну копию каждой уникальной строки.

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

Почему это работает только с иммутабельными строками

Если бы строки можно было менять, то изменение одной строки повлияло бы на все остальные, которые ссылаются на неё:

// Гипотетически — если бы строки были мутабельны
String a = "Hello";
String b = "Hello"; // та же ссылка из пула
a.changeTo("World"); // сломает b тоже!

Метод intern()

String s1 = new String("Hello"); // новый объект в heap
String s2 = s1.intern();          // добавляет в пул, возвращает ссылку
String s3 = "Hello";              // из пула
System.out.println(s2 == s3);     // true

Middle Level

Механизм работы

  1. При компиляции — все строковые литералы попадают в таблицу констант класса
  2. При загрузке — JVM проверяет пул: если строка есть — возвращает ссылку, нет — создаёт новую
  3. Во время выполненияintern() добавляет строку из heap в пул

Эволюция памяти

  • Java 6: String Pool был в PermGen (ограниченный размер, частые OOM)
  • Java 7u6+: String Pool переехал из PermGen в обычный Heap (управляется GC)

Преимущества

  • Экономия памяти — дубликаты строк не создаются
  • Быстрое сравнение — интернированные строки можно сравнивать через == за O(1) (одна инструкция CPU — сравнение ссылок), тогда как equals() проходит по всем символам.
  • Кэширование hashCode — вычисляется один раз

Когда использовать intern()

  • Много повторяющихся строк (ключи, константы конфигурации)
  • Ключи в HashMap с миллиардами записей (экономия на дубликатах)

Senior Level

Связь с иммутабельностью

Иммутабельность — необходимое условие для String Pool. Паттерн Flyweight на уровне языка работает только потому, что Java гарантирует: содержимое String никогда не изменится.

Производительность

  • Сравнение через == для интернированных строк — O(1), но в бизнес-логике всё равно используйте equals()
  • Кэшированный hashCode ускоряет работу HashMap — повторные lookup’и не требуют пересчёта

Риски intern()

  • Memory leak — строки из пула не удаляются GC пока жив ClassLoader
  • PermGen/Heap OOM — слишком много уникальных строк через intern() может переполнить память
  • В Java 7+ пул в Heap, но строки всё ещё могут жить очень долго

Резюме для Senior

  • String Pool — Flyweight паттерн на уровне языка
  • Работает только благодаря гарантий иммутабельности
  • Пул в Heap (Java 7+), управляется GC
  • intern() — мощный, но опасный инструмент: следите за объёмом уникальных строк

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

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

  • String Pool — хранилище уникальных строк, работает ТОЛЬКО благодаря иммутабельности (Flyweight)
  • Литералы попадают в пул при загрузке класса, intern() добавляет строку из heap
  • Java 6: пул в PermGen (частые OOM); Java 7+: пул в Heap (управляется GC)
  • Сравнение интернированных строк через == — O(1), но в бизнес-логике используйте equals()
  • String кэширует hashCode — вычисляется один раз, ускоряет HashMap
  • Риски intern(): memory leak, Heap OOM при слишком большом количестве уникальных строк

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

  • Почему пул невозможен без иммутабельности? — Изменение одной строки сломает все ссылки на неё
  • Когда использовать intern()? — Много повторяющихся строк, ключи в огромных HashMap
  • intern() — это безопасно? — Строки из пула не удаляются GC пока жив ClassLoader — risk of OOM
  • Compact Strings влияют на пул? — Нет, пул работает независимо; Compact Strings экономят 50% памяти

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

  • «String Pool в PermGen» — с Java 7+ в Heap
  • «intern() всегда ускоряет» — при злоупотреблении вызывает OOM
  • «Сравнивать строки через == нормально после intern()» — в бизнес-логике всегда equals()
  • «Пул копирует строки» — литералы помещаются в пул при загрузке класса

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

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