Ответ 1
JLS не гарантирует повторного использования подстрок. Здесь "содержать" означает только, что класс упоминает то же самое строковое литералы где-то. Он не используется в смысле "подстроки".
Я знаю, что вы делаете
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";
Сколько экземпляров создано?
s1
и s2
(тогда s3
создается повторное использование ссылок s1
и s2
)JLS не гарантирует повторного использования подстрок. Здесь "содержать" означает только, что класс упоминает то же самое строковое литералы где-то. Он не используется в смысле "подстроки".
Каждый файл класса содержит список всех строковых литералов или других констант, используемых в этом классе (за исключением небольших числовых констант, встроенных в поток команд). Если элемент 19 в списке является строковым литералом "Freddy"
, а локальная переменная Fred
имеет индекс 6, то байт-код, сгенерированный для Fred="Freddy";
, скорее всего будет ldc 19
/astore 6
.
Когда класс загружается, система будет строить таблицу всех констант и - для ссылочных типов - объекты, идентифицированные им. Если не существует экземпляра строкового литерала, система добавит его в таблицу интернирования и сохранит ссылку на это. При генерации машинного кода ldc 19
затем будет заменен инструкцией для загрузки соответствующей ссылки.
Важно то, что к моменту запуска любого из кода в классе объекты были созданы для всех строковых литералов, поэтому оператор вроде Fred="Freddy";
просто сохранит ссылку на уже существующий String
объект, содержащий Freddy
, вместо создания нового объекта String
.
Если s3
повторно использовать s1
и s2
экземпляры, то s3
не будет физически представлен как непрерывный массив символов, а скорее будет составным String
объектов String
.
Теперь представьте, что влияние производительности на доступ к отдельным символам в таком потоке, основанном на строках, основано на индексах, будет фактически включать сравнение значения индекса с размером первой строки, затем вычисление смещения, которое станет индексом для второй строки и т.д.
На самом деле, имеет смысл обратное: для "hi there"
(s3
) может быть выделена только одна базовая последовательность char, а s1
и s2
могут просто хранить свои длины и адреса первого символа внутри этой строки. Но я полагаю, что для jvm было бы сложной и дорогостоящей работой по определению "встраиваемых" кандидатов и что стоимость перевешивала бы потенциальную выгоду.