Короткий ответ
String Pool (пул строк) — специальная область памяти в куче, где JVM хранит строковые литералы, чтобы одинаковые строки не дублировались. Когда код встречает литерал "java", JVM проверяет пул: если такая строка уже есть, переменная получает ссылку на существующий объект, если нет — строка создаётся и помещается в пул. Поэтому сравнение == двух одинаковых литералов даёт true.
Как это работает подробнее
Создание через new String("java") работает иначе: конструктор всегда создаёт новый объект в обычной части кучи, даже если такая строка уже есть в пуле, поэтому new String("java") == "java" даёт false. Переместить строку в пул можно вручную методом intern(), который возвращает канонический объект из пула. До Java 7 пул находился в PermGen, с Java 7 его перенесли в обычную кучу — теперь сборщик мусора может удалять неиспользуемые интернированные строки.
- Интернирование литералов — одинаковые литералы по всей программе разделяют один объект и экономят память.
- new String(...) — всегда отдельный объект в куче, мимо пула, даже при существующем литерале.
- intern() — ручное помещение строки в пул с возвратом канонического объекта.
- Расположение — до Java 7 PermGen, с Java 7 обычная куча.
Пример кода
public class StringPoolDemo {
public static void main(String[] args) {
String s1 = "java"; // создаётся или находится в пуле
String s2 = "java"; // берётся та же ссылка из пула
String s3 = new String("java"); // новый объект в куче, мимо пула
System.out.println(s1 == s2); // true — один объект из пула
System.out.println(s1 == s3); // false — разные объекты
System.out.println(s1 == s3.intern()); // true — канонический объект
}
}Что использовать на практике
- Сравнивай строки по содержимому через equals(), а не через ==.
- Избегай new String("литерал") — используй литералы или StringBuilder.
- Не вызывай intern() в горячем коде без нужды: это расходы на поиск в пуле.
Подводные камни
- new String("java") == "java" всегда false: конструктор создаёт объект мимо пула.
- Строки из runtime-конкатенации не обязаны попадать в пул — == может дать false для одинакового содержимого.
- Чрезмерный intern() раздувает пул и способен переполнить память (до Java 7 — PermGen).
Как отвечать на собеседовании
- Определи пул: область памяти для литералов → объясни переиспользование и == для одинаковых литералов → разбери new String(...) и intern() → упомяни перенос из PermGen в кучу с Java 7 → дай правило: содержимое сравнивать equals().