2016-07-15 11 views
19

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

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

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

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

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

AFAIK, что не говорит происходит с быть та же строка буквальное, он говорит содержит.

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

Давать этот фрагмент:

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

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

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

Он, вероятно, означает, что «виртуальная машина содержит ..», а не строка содержит другую строку –

+1

Я не уверен, поэтому комментарий вместо ответа. Но я думаю, что «содержать» частично ошибочно, и ваш пример действительно дает три экземпляра. – glglgl

+0

@glglgl на самом деле это то, что * моя логика * говорит, но может быть JVM достаточно умным, чтобы создать 's3' в качестве ссылки на' s1' + 's2' ?? –

ответ

17

JLS не гарантирует повторное использование подстроки вообще. Здесь «содержать» означает только, что класс упоминает тот же самый строковый литерал где-то. Это не, используемый в смысле «подстрока».

+2

В частности, «любой другой код [..], который содержит ** тот же строковый литерал **« _ (выделение мое) –

+1

, когда вы говорите * не гарантирует повторное использование подстрок * означает, что это может случиться иногда? –

+3

@JordiCastilla: Я не думаю, что какая-либо текущая ВМ повторно использует подстроки, но это возможно (и предыдущие итерации OpenJDK, например, иногда делили базовый символ [], когда две строки были подстроками друг друга). Обратите внимание, что вы все равно будете наблюдать отдельные экземпляры 'String', и нет общедоступного API для определения того, происходит ли это (т. Е. Вы не сможете сказать без какой-либо обманчивости). –

3

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

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

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

2

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

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

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

+1

Ну, до того, как Java 7 был использован метод подстроки таким образом, чтобы он возвращал строку, поддерживаемую исходным массивом символов String, но даже это было отброшено, потому что это принесло больше вреда, чем пользы (большие тексты могли быть например, поддерживая ссылку на некоторую крошечную подстроку) – Hulk

+1

@Hulk: [изменение в Java7update6] (http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4513622). Это не только проблема gc; он требует, чтобы каждая строка несла поле 'offset' и' length' для единственной цели одной операции, 'substring'. Кроме того, функция дедупликации строк для последних JVM выгодна из упрощенного макета объекта, поскольку достаточно одного «cas» в поле «value». – Holger