Подтвердить что ты не робот

Как повторное использование JVM интернированных строковых подстрок?

Я знаю, что вы делаете

for (condition) {
    String s = "hi there";
}

Только один экземпляр String создается во всех итерациях, в отличие от String s = new String("hi there");, который создаст новый экземпляр на каждой итерации.

Но, читая Effective Java от Джошуа Блоха: Глава 2, пункт 5 (стр. 20), он гласит:

Кроме того, гарантируется, что объект будет повторно используемый любым другим кодом, работающим на той же виртуальной машине, который имеет место с содержать тот же строковый литерал [JLS, 3.10.5].

AFAIK, который не говорит, имеет be тот же строковый литерал, он говорит, что содержит.

Чтение [JLS, 3.10.5] не может найти никакой точной ссылки на это, и у меня есть сомнения.

Предоставление этого фрагмента:

String s1 = "hi ";
String s2 = "there";
String s3 = "hi there";

Сколько экземпляров создано?

  • 3 экземпляра (таким образом, фраза не очень точная).
  • 2 экземпляра, s1 и s2 (тогда s3 создается повторное использование ссылок s1 и s2)
4b9b3361

Ответ 1

JLS не гарантирует повторного использования подстрок. Здесь "содержать" означает только, что класс упоминает то же самое строковое литералы где-то. Он не используется в смысле "подстроки".

Ответ 2

Каждый файл класса содержит список всех строковых литералов или других констант, используемых в этом классе (за исключением небольших числовых констант, встроенных в поток команд). Если элемент 19 в списке является строковым литералом "Freddy", а локальная переменная Fred имеет индекс 6, то байт-код, сгенерированный для Fred="Freddy";, скорее всего будет ldc 19/astore 6.

Когда класс загружается, система будет строить таблицу всех констант и - для ссылочных типов - объекты, идентифицированные им. Если не существует экземпляра строкового литерала, система добавит его в таблицу интернирования и сохранит ссылку на это. При генерации машинного кода ldc 19 затем будет заменен инструкцией для загрузки соответствующей ссылки.

Важно то, что к моменту запуска любого из кода в классе объекты были созданы для всех строковых литералов, поэтому оператор вроде Fred="Freddy"; просто сохранит ссылку на уже существующий String объект, содержащий Freddy, вместо создания нового объекта String.

Ответ 3

Если s3 повторно использовать s1 и s2 экземпляры, то s3 не будет физически представлен как непрерывный массив символов, а скорее будет составным String объектов String.

Теперь представьте, что влияние производительности на доступ к отдельным символам в таком потоке, основанном на строках, основано на индексах, будет фактически включать сравнение значения индекса с размером первой строки, затем вычисление смещения, которое станет индексом для второй строки и т.д.

На самом деле, имеет смысл обратное: для "hi there" (s3) может быть выделена только одна базовая последовательность char, а s1 и s2 могут просто хранить свои длины и адреса первого символа внутри этой строки. Но я полагаю, что для jvm было бы сложной и дорогостоящей работой по определению "встраиваемых" кандидатов и что стоимость перевешивала бы потенциальную выгоду.