Выполняется ли интернирование строк во время компиляции в Java?

Я действительно смущен тем, как string interning работает на Java. Когда я пишу:

String a = "ABC";
String b = "ABC";

if (a==b)
    System.out.println("Equal");

Сохраняет ли компилятор строковый литерал "ABC" в пул строковых констант во время компиляции?

Это звучит нелогично, потому что я думал, что строковый постоянный пул был создан JVM во время выполнения, и я не вижу, как это возможно, если это делается во время компиляции, поскольку компилятор Java даже не вызывает JVM.

Если это не сделано во время компиляции, и это выполняется во время выполнения, то почему следующее возвращается false (взято из этого ответа)?

// But .substring() is invoked at runtime, generating distinct objects
"test" == "!test".substring(1) // --> false

Если это выполняется во время выполнения, то почему JVM не может определить, что они являются одной и той же строкой?

Я действительно смущен тем, как работает интерпретация строк в Java и где хранится именно пул строк Java.

Ответы

Ответ 1

Компилятор помещает литеральные строки в файл класса (и только уникальные, он объединяет все эквивалентные литералы); JVM загружает эти строки в пул строк при загрузке файла класса.

Если это выполняется во время выполнения, то почему JVM не может определить, что они являются одной и той же строкой.

Поскольку строка, возвращаемая .substring, не была интернирована, и это другой объект, чем эквивалентная строка "test" в пуле строк. Если вы интернировали его, вы получите true:

"test" == "!test".substring(1).intern() // true

Разделы §4.4 JLS и §5.3 спецификации JVM выглядят релевантными.


Просто чтобы быть ясным: правильный способ сравнения строк в Java - использовать метод .equals или аналогичный, а не ==. Использование == со строковыми экземплярами обычно неверно. (Если вы не играете с пониманием, когда и как вещи интернированы...)

Ответ 2

Я проверил .class для

String a = "ABC";
String b = "ABC";

и нашел в нем только одну "ABC". Это javac создает одну константу той же строки во время компиляции.

Но если 2 или более классы имеют одну и ту же константу "ABC", то JVM поместит их в одно и то же место в пуле строк