Что такое String Interning в Java, когда я должен его использовать и почему ?
java
string
string-interning
saplingPro
источник
источник
String a = new String("abc");
String b = new String("abc");
тогдаa.intern() == b.intern()
String.intern()
от тогоClassLoader
, что означает, что разные загрузчики классов создают "разные"String
, вызывая разныеintern
?Ответы:
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#intern ()
По сути, выполнение String.intern () для ряда строк гарантирует, что все строки, имеющие одинаковое содержимое, совместно используют одну и ту же память. Таким образом, если у вас есть список имен, где «Джон» появляется 1000 раз, при интернировании вы гарантируете, что только один «Джон» фактически выделен памяти.
Это может быть полезно для уменьшения требований к памяти вашей программы. Но имейте в виду, что JVM поддерживает кеш в постоянном пуле памяти, размер которого обычно ограничен по сравнению с кучей, поэтому не следует использовать intern, если у вас не слишком много повторяющихся значений.
Подробнее об ограничениях памяти при использовании intern ()
- От: http://www.codeinstructions.com/2009/01/busting-javalangstringintern-myths.html
С JDK 7 (я имею в виду в HotSpot) что-то изменилось.
-- Из Java SE 7 Возможности и улучшения
Обновление: Interned строки хранятся в основной куче начиная с Java 7 и далее. http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html#jdk7changes
источник
char[]
вместоString
чувствительного текста и обнулить его, как только он больше не нужен.Есть несколько «броских интервью» вопросов, например, почему вы получаете равных! если вы выполните приведенный ниже фрагмент кода.
Если вы хотите сравнить строки, вы должны использовать
equals()
. Выше будет печатать равно, потому что компилятор для васtestString
уже интернирован . Вы можете интернировать строки самостоятельно, используя метод intern, как показано в предыдущих ответах ....источник
equals
метод. Возможно, вы захотите добавитьnew String()
сравнение, чтобы показать разницу более четко.JLS
JLS 7 3.10.5 определяет его и дает практический пример:
JVMs
JVMS 7 5.1 говорит, что интернирование реализовано магически и эффективно с выделенной
CONSTANT_String_info
структурой (в отличие от большинства других объектов, которые имеют более общие представления):Bytecode
Давайте декомпилируем некоторый байт-код OpenJDK 7, чтобы увидеть интернирование в действии.
Если мы декомпилируем:
у нас на постоянном пуле:
и
main
:Обратите внимание, как:
0
и3
:ldc #2
загружается одна и та же константа (литералы)12
: создается новый экземпляр строки (с#2
аргументом as)35
:a
иc
сравниваются как обычные объекты сif_acmpne
Представление константных строк довольно волшебно в байт-коде:
new String
)и приведенная выше цитата JVMS, кажется, говорит, что всякий раз, когда Utf8, на который указывают, является тем же самым, тогда идентичные экземпляры загружаются
ldc
.Я сделал аналогичные тесты для полей, и:
static final String s = "abc"
указывает на таблицу констант через атрибут ConstantValueldc
Вывод : есть прямая поддержка байт-кода для пула строк, и представление памяти эффективно.
Бонус: сравните это с целочисленным пулом , который не имеет прямой поддержки байт-кода (т.е. не имеет
CONSTANT_String_info
аналогов).источник
Обновление для Java 8 или плюс . В Java 8 пространство PermGen (Permanent Generation) удаляется и заменяется метапространством. Память пула строк перемещается в кучу JVM.
По сравнению с Java 7 размер пула строк увеличен в куче. Следовательно, у вас больше места для внутренних строк, но у вас меньше памяти для всего приложения.
Еще одна вещь, вы уже знаете, что при сравнении 2 (ссылок) объектов в Java, «
==
» используется для сравнения ссылок объекта, «equals
» используется для сравнения содержимого объекта.Давайте проверим этот код:
Результат:
value1 == value2
---> правдаvalue1 == value3
---> ложьvalue1.equals(value3)
---> правдаvalue1 == value3.intern()
---> правдаВот почему вы должны использовать '
equals
', чтобы сравнить 2 объекта String. И вот какintern()
это полезно.источник
Интернирование строк - это метод оптимизации компилятором. Если у вас есть два одинаковых строковых литерала в одном модуле компиляции, то сгенерированный код гарантирует, что для всего экземпляра этого литерала (символы, заключенные в двойные кавычки) внутри сборки создан только один строковый объект.
Я из C # фона, поэтому я могу объяснить, приведя пример из этого:
вывод следующих сравнений:
Примечание 1 : объекты сравниваются по ссылке.
Примечание 2 : typeof (int). Имя оценивается методом отражения, поэтому оно не оценивается во время компиляции. Вот эти сравнения сделаны во время компиляции.
Анализ результатов: 1) истина, потому что они оба содержат одинаковые литералы, и поэтому сгенерированный код будет иметь только один объект, ссылающийся на «Int32». См Примечание 1 .
2) истина, потому что проверяется содержимое обоих значений, что является одинаковым.
3) ЛОЖЬ, потому что str2 и obj не имеют одинаковые литералы. Смотрите примечание 2 .
источник
источник
Из книги Deshmukh программиста OCP Java SE 11 я нашел простейшее объяснение Interning, которое заключалось в следующем: поскольку строки являются объектами и поскольку все объекты в Java всегда хранятся только в пространстве кучи, все строки хранятся в пространстве кучи. Однако Java хранит строки, созданные без использования ключевого слова new, в специальной области пространства кучи, которая называется «пул строк». Java сохраняет строки, созданные с использованием нового ключевого слова, в обычном пространстве кучи.
Назначение пула строк - поддерживать набор уникальных строк. Каждый раз, когда вы создаете новую строку без использования ключевого слова new, Java проверяет, существует ли такая же строка в пуле строк. Если это так, Java возвращает ссылку на тот же объект String, а если нет, Java создает новый объект String в пуле строк и возвращает его ссылку. Так, например, если вы дважды используете строку «hello» в своем коде, как показано ниже, вы получите ссылку на одну и ту же строку. На самом деле мы можем проверить эту теорию, сравнив две разные ссылочные переменные с помощью оператора ==, как показано в следующем коде:
Оператор == просто проверяет, указывают ли две ссылки на один и тот же объект, и возвращает true, если они это делают. В приведенном выше коде str2 получает ссылку на тот же объект String, который был создан ранее. Однако str3 и str4 получают ссылки на два совершенно разных объекта String. Вот почему str1 == str2 возвращает true, а str1 == str3 и str3 == str4 возвращают false. На самом деле, когда вы делаете новую строку ("привет"); два объекта String создаются вместо одного, если это первый раз, когда строка «hello» используется в любом месте программы - один в пуле строк из-за использования строки в кавычках и один в обычном пространстве кучи, потому что использования нового ключевого слова.
Объединение строк - это способ сохранения программной памяти в Java, избегая создания нескольких объектов String, содержащих одно и то же значение. Можно получить строку из пула строк для строки, созданной с помощью ключевого слова new, с помощью метода intern строки. Это называется «интернирование» строковых объектов. Например,
источник