Как работает String pool и как это связано с иммутабельностью?
Если бы строки можно было менять, то изменение одной строки повлияло бы на все остальные, которые ссылаются на неё:
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
Механизм работы
- При компиляции — все строковые литералы попадают в таблицу констант класса
- При загрузке — JVM проверяет пул: если строка есть — возвращает ссылку, нет — создаёт новую
- Во время выполнения —
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]]