← Назад к вопросам

Поместится ли новый объект, созданный при конкатенации строк "ABCD" и "ABC" в String Pool

1.8 Middle🔥 201 комментариев
#Docker, Kubernetes и DevOps#REST API и микросервисы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ответ: Поместится ли новый объект при конкатенации строк в String Pool

Краткий ответ

Нет, при конкатенации строк "ABCD" + "ABC" результат НЕ поместится в String Pool. Результатом будет новый объект String в heap памяти, а не в String Pool. Это частая ошибка на собеседованиях.

Что такое String Pool?

String Pool (String Constant Pool) — это специальная область памяти, где JVM хранит строки для оптимизации памяти:

public class StringPoolBasics {
    public static void main(String[] args) {
        // Обе переменные указывают на ОДИН объект в String Pool
        String s1 = "Hello";
        String s2 = "Hello";
        
        System.out.println(s1 == s2);  // true (одна ячейка памяти)
        System.out.println(s1.equals(s2));  // true
        
        // Но если создать через new, то это новый объект в heap
        String s3 = new String("Hello");
        System.out.println(s1 == s3);  // false (разные ячейки памяти)
        System.out.println(s1.equals(s3));  // true (одинаковое содержимое)
    }
}

Конкатенация и String Pool

Вот здесь начинается путаница. Нужно различать два случая:

Случай 1: Конкатенация в compile-time (строковые литералы)

Если компилятор может определить результат ДО запуска программы, то он оптимизирует и помещает результат в String Pool:

public class CompileTimeConcat {
    public static void main(String[] args) {
        // ✅ Compile-time конкатенация
        String result = "AB" + "CD";
        String expected = "ABCD";
        
        System.out.println(result == expected);  // true!
        // Компилятор заменил ("AB" + "CD") на "ABCD" ДО запуска
        // Это эквивалентно:
        // String result = "ABCD";
        // Оба указывают на один объект в String Pool
    }
}

Почему это работает? Компилятор видит две строки "AB" и "CD" и вычисляет результат на этапе компиляции. Результат "ABCD" становится строковым литералом.

Случай 2: Конкатенация в run-time (с переменными)

Если хотя бы одна из строк — это переменная, то результат вычисляется в runtime и не попадает в String Pool:

public class RuntimeConcat {
    public static void main(String[] args) {
        String a = "AB";
        String b = "CD";
        
        // ❌ Runtime конкатенация
        String result = a + b;
        String expected = "ABCD";
        
        System.out.println(result == expected);  // false!
        System.out.println(result.equals(expected));  // true (содержимое одинаково)
        
        // result указывает на новый объект в heap
        // expected указывает на объект в String Pool
    }
}

Ваш конкретный пример

Для вопроса: "ABCD" + "ABC"

public class YourExample {
    public static void main(String[] args) {
        // ✅ ОБА операнда - это строковые ЛИТЕРАЛЫ (известны в compile-time)
        String result = "ABCD" + "ABC";
        
        // Компилятор оптимизирует это и заменяет на:
        // String result = "ABCDABC";
        
        // Поэтому результат БУДЕТ в String Pool
        String pool = "ABCDABC";
        System.out.println(result == pool);  // true!
    }
}

Но вот более хитрый пример

public class TrickyExample {
    public static void main(String[] args) {
        // НЕПРАВИЛЬНОЕ понимание вопроса
        final String a = "ABCD";
        final String b = "ABC";
        String result1 = a + b;  // ✅ Pool! (финальные переменные известны в compile-time)
        System.out.println(result1 == "ABCDABC");  // true
        
        // ПРАВИЛЬНОЕ понимание
        String c = "ABCD";
        String d = "ABC";
        String result2 = c + d;  // ❌ NOT in Pool! (обычные переменные)
        System.out.println(result2 == "ABCDABC");  // false
    }
}

Как это работает под капотом

Java < 9: Использование StringBuffer/StringBuilder

При конкатенации с переменными компилятор генерирует:

// Исходный код
String result = a + b + c;

// Компилятор переводит в:
String result = new StringBuilder()
    .append(a)
    .append(b)
    .append(c)
    .toString();

// toString() создаёт NEW строку в heap, а не в Pool

Java 9+: Использование invokedynamic и StringConcatFactory

// Компилятор использует более эффективный способ
// но результат всё равно остаётся в heap, не в Pool

Проверка в памяти

public class MemoryCheck {
    public static void main(String[] args) {
        // Метод intern() добавляет строку в String Pool
        
        String a = "ABCD";
        String b = "ABC";
        String concat = a + b;
        
        // ДО intern()
        System.out.println(concat == "ABCDABC");  // false
        
        // ПОСЛЕ intern() — добавляем в Pool
        String interned = concat.intern();
        System.out.println(interned == "ABCDABC");  // true
        System.out.println(interned == concat);  // true (теперь они указывают на одно место)
    }
}

Таблица: Когда строка попадает в String Pool?

Способ созданияПопадает в Pool?Пример
Строковый литерал✅ ДаString s = "Hello";
Литерал + Литерал✅ Да"AB" + "CD""ABCD"
Переменная + Переменная❌ Нетa + b
Литерал + Переменная❌ Нет"AB" + b
new String()❌ Нетnew String("Hello")
intern()✅ Даs.intern()
.replaceAll()❌ Нет (если изменилось)s.replaceAll(...).intern()
StringBuilder.toString()❌ Нетsb.toString()

Визуальное объяснение

╔════════════════════════════════════════╗
║          STRING POOL (Metaspace)       ║
║                                        ║
║  "ABCD" → address 0x001              ║
║  "ABC"  → address 0x002              ║
║  "ABCDABC" (literal) → address 0x003 ║
╚════════════════════════════════════════╝

╔════════════════════════════════════════╗
║      HEAP (обычная память объектов)   ║
║                                        ║
║  "ABCDABC" (из конкатенации)         ║
║  → address 0x1000                     ║
╚════════════════════════════════════════╝

Практический пример с вашим вопросом

public class YourQuestionAnalyzed {
    public static void main(String[] args) {
        // Вопрос: Поместится ли результат конкатенации
        // "ABCD" + "ABC" в String Pool?
        
        // ОТВЕТ: ДА, поместится в String Pool
        // Потому что оба операнда - это строковые ЛИТЕРАЛЫ
        // Компилятор может вычислить результат ДО запуска
        // и создаст литерал "ABCDABC"
        
        String result = "ABCD" + "ABC";
        String poolVersion = "ABCDABC";
        
        System.out.println(result == poolVersion);  // Output: true
        System.out.println(System.identityHashCode(result));
        System.out.println(System.identityHashCode(poolVersion));
        // Оба вернут ОДИНАКОВЫЙ хеш (одна ячейка памяти)
    }
}

Но если бы это были переменные:

public class IfTheyWereVariables {
    public static void main(String[] args) {
        String a = "ABCD";
        String b = "ABC";
        String result = a + b;  // Переменные!
        String poolVersion = "ABCDABC";
        
        System.out.println(result == poolVersion);  // Output: false
        System.out.println(System.identityHashCode(result));      // Разные
        System.out.println(System.identityHashCode(poolVersion)); // значения
    }
}

Ключевые моменты для собеседования

  1. Compile-time vs Runtime: Если компилятор может вычислить результат — String Pool. Если нет — heap.

  2. Литералы vs Переменные: "ab" + "cd" (литералы) → Pool. a + b (переменные) → heap.

  3. final переменные: Если переменная final и инициализирована литералом, она ведёт себя как литерал.

  4. intern(): Вы можете принудительно добавить строку в Pool через .intern(), но это редко нужно.

  5. Performance: String Pool экономит память для известных литералов. Это хорошо для приложений с много текстом.

Итог

Для вашего конкретного вопроса: ДА, результат "ABCD" + "ABC" поместится в String Pool, потому что оба операнда известны в compile-time. Но если это были переменные, то НЕТ, результат был бы создан в обычной heap памяти.