Почему String в Java неизменяемый и что такое пул строк?
Короткий ответ
- Объект String нельзя изменить после создания — все методы возвращают новую строку
- Неизменяемость даёт безопасность, потокобезопасность и кэширование hashCode
- Литералы складываются в пул строк и переиспользуются
- new String("a") создаёт отдельный объект вне пула
- Сравнивать строки нужно через equals, а не ==
- Для частых конкатенаций в цикле — StringBuilder
String неизменяем ради безопасности, кэширования и пула строк; сравнение — только через equals.
Как сказать вслух
пример ответаСтрока в Java неизменяема: любой метод вроде replace или concat возвращает новый объект, а исходный не трогается. Это даёт три выгоды: строки можно безопасно шарить между потоками, их hashCode кэшируется, и одинаковые литералы переиспользуются через пул строк. Поэтому сравнивать строки надо через equals — оператор сравнения проверяет только, один ли это объект.
Подробный ответ
Основной ответ
String — финальный класс с финальным внутренним массивом (с Java 9 это byte[] благодаря compact strings); ни один метод не меняет содержимое, а возвращает новый объект. Неизменяемость даёт: безопасное использование как ключей HashMap (hashCode вычисляется один раз и кэшируется), потокобезопасность без синхронизации, защиту в API (путь, имя класса не подменят после проверки). Пул строк — таблица в куче, куда попадают все литералы: два одинаковых литерала ссылаются на один объект, поэтому == для них случайно «работает». new String() создаёт копию вне пула, intern() возвращает экземпляр из пула. Конкатенация в цикле порождает мусорные объекты — для этого есть StringBuilder.
Ключевые моменты
- Зачем неизменяемость. Кэш hashCode, потокобезопасность, безопасность API и возможность пула.
- Пул строк. Литералы дедуплицируются; intern() добавляет/находит строку в пуле вручную.
- equals vs ==. == сравнивает ссылки; содержимое — только equals/equalsIgnoreCase.
- StringBuilder. Изменяемый буфер для сборки строк в циклах; компилятор сам оптимизирует только простые выражения.
Практический контекст
Классический вопрос первого раунда. На практике тема всплывает в багах сравнения через == (особенно после десериализации или new String) и в перформансе — конкатенация в цикле на горячем пути. Интервьюер смотрит, можете ли вы объяснить «почему» неизменяемости, а не только факт, и знаете ли разницу литерала и new String.
Частые ошибки
- Сравнивают строки через == и уверены, что это всегда работает из-за пула
- Называют String изменяемым, путая со StringBuilder
- Говорят, что пул строк находится в PermGen — с Java 7 он в куче