Как происходит выделение памяти для строки (String) в Java?

«Как происходит выделение памяти для строки (String) в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Выделение памяти для строки в Java зависит от способа её создания и связано с двумя областями памяти: куча (heap) и пул строк (String Pool).

1. Создание строки-литерала:

String s1 = "Hello";
  • Строка "Hello" ищется в String Pool (специальная область heap для уникальных литералов).
  • Если найдена — s1 получает ссылку на существующий объект.
  • Если не найдена — объект создаётся в пуле, и ссылка сохраняется там.
  • Цель: экономия памяти за счёт повторного использования неизменяемых строк.

2. Явное создание через new:

String s2 = new String("Hello");
  • Всегда создаёт новый объект в куче (heap), даже если идентичная строка есть в пуле.
  • Ссылка на литерал "Hello" из пула используется для инициализации, но s2 указывает на отдельный объект.

3. Операции, изменяющие строку (конкатенация, substring в старых версиях):

String s3 = s1 + " World"; // "Hello World"
  • Так как строки неизменяемы (immutable), любая операция, модифицирующая содержимое, создаёт новый объект String в куче.
  • Компилятор может оптимизировать конкатенацию литералов, но в общем случае это дорогая операция.

Практические следствия и best practices:

  • Для многократного изменения строки используйте StringBuilder (не потокобезопасный) или StringBuffer (потокобезопасный).
  • Сравнение строк: s1.equals(s2) для сравнения содержимого, s1 == s2 — для проверки, ссылаются ли переменные на один и тот же объект в памяти.
  • Метод String.intern() позволяет вручную поместить строку в пул и получить на неё ссылку.