Конкатенация Java-строк и интернирование

Вопрос 1

String a1 = "I Love" + " Java";
String a2 = "I Love " + "Java";
System.out.println( a1 == a2 ); // true

String b1 = "I Love";
b1 += " Java";
String b2 = "I Love ";
b2 += "Java";
System.out.println( b1 == b2 ); // false

В первом случае я понимаю, что это конкатенация двух строковых литералов, поэтому результат "Я люблю Java" будет интернирован, что даст результат true. Однако я не уверен насчет второго случая.

вопрос 2

String a1 = "I Love" + " Java"; // line 1
String a2 = "I Love " + "Java"; // line 2

String b1 = "I Love";
b1 += " Java";
String b2 = "I Love ";
b2 += "Java";
String b3 = b1.intern();
System.out.println( b1 == b3 ); // false

Выше возвращается false, но если я закомментирую строки 1 и 2, он возвращает true. Это почему?

3 ответа

Решение

Первая часть вашего вопроса проста: компилятор Java рассматривает конкатенацию нескольких строковых литералов как единый строковый литерал, т.е.

"I Love" + " Java"

а также

"I Love Java"

два одинаковых строковых литерала, которые правильно интернированы

Такое же поведение интернирования не относится к += операция на строках, так b1 а также b2 на самом деле строятся во время выполнения.

Вторая часть сложнее. Напомним, что b1.intern() может вернуться b1 или какой-то другой String объект, который равен ему. Когда вы держите a1 а также a2, ты получаешь a1 вернуться от звонка b1.intern(), Когда вы комментируете a1 а также a2, нет существующей копии для возврата, поэтому b1.intern() возвращает тебя b1 сам.

Из стажера () документов

Все литеральные строки и строковые константные выражения интернированы. Строковые литералы определены в разделе 3.10.5 Спецификации языка Java™.

И из JLS 3.10.5

  • Строки, вычисленные с помощью константных выражений (§15.28), вычисляются во время компиляции, а затем обрабатываются, как если бы они были литералами.
    • Строки, вычисленные путем конкатенации во время выполнения, создаются заново и поэтому различаются.

Ваша строка b1 на самом деле не интернирована. Отсюда и разница.

Ответ на вопрос 1:

Вы не можете сравнить две строки с ==, == сравнивает два примитивных типа данных (int, long, float, double и boolean) или ссылки на объекты. Это означает, что если эталонные переменные (a1, a2, b1, b2) не имеют одинаковую ссылку (то есть они не указывают на один и тот же объект в памяти), они не равны (сравнение с ==).

Если бы вы сравнили с b1.equals(b2), выражение будет истинным, поскольку данные объекта совпадают.

В первом случае Java достаточно умен, чтобы объединять строки перед выделением им некоторой памяти (даже перед компиляцией), что означает, что обе строки хранятся по одному адресу. Следовательно, переменные a1 и a2 ссылаются на один и тот же объект и равны (==).

Во втором случае вы сначала назначаете переменным другое значение (в отличие от первого случая). Это означает, что они получают отдельный адрес в памяти. Даже если вы измените значение, чтобы они были одинаковыми, адрес не изменится и сравнение с == оценивается как ложное. Это происходит во время выполнения.

Что касается вопроса 2: @dasblinkenlight уже дал хороший ответ на это.

Другие вопросы по тегам