Как интернирование строк работает в Java 7+?

Итак, я понимаю, что вопросы, которые я собираюсь задать, относятся к теме, которую раз за разом избивали до смерти, однако, даже после прочтения всех ответов и документации, которые я смог найти, я все еще немного сбит с толку. интернирование строк. Возможно, это из-за моего непонимания JVM; возможно, это связано с изменениями, внесенными в Java 7, которые обесценивают многие из вышеупомянутых ответов и документации. В любом случае, я застрял, и я надеюсь, что кто-то может помочь мне понять концепцию немного яснее...

String a = "text";
String b = new String("text");

В приведенном выше примере я понимаю, что будут созданы два объекта String. Я также понимаю, что в памяти будет только один массив символов, содержащий последовательность 't', 'e', 'x', and 't'.

Однако где в памяти на самом деле хранится каждый из строковых объектов?

Если то, что я прочитал, я прочитал правильно: референт переменной a будет храниться в пуле констант, тогда как референт b будет храниться в куче, верно?

Если это так, я не понимаю, как внутренний пул поддерживает интернированные строки. Отслеживает ли он строки, определенные в пуле констант, и те, которые были вручную интернированы (вызваны .intern()) из кучи? Создает ли JVM строковые объекты, определенные в пуле констант, и загружает ли их во внутренний пул? Я в замешательстве, как это все работает...

Опять же, извините, что задаю такие запутанные/глупые вопросы, просто я относительно плохо знаком со структурой и внутренней работой JVM, и от многих из них у меня кружится голова. Спасибо!


person kylemart    schedule 30.11.2014    source источник
comment
я предлагаю вам прочитать все ответы здесь   -  person Sainath S.R    schedule 30.11.2014
comment
В отношении интернирования строк в Java 7 и 8 ничего фундаментального не изменилось по сравнению со старыми версиями.   -  person Jesper    schedule 30.11.2014


Ответы (2)


В java есть вещь, называемая String Memory Pool, когда вы объявляете:

String str1="abc";

Он идет в этот пул памяти, а не в кучу. Но когда вы пишете:

String str2=new String("abc");

Он создает полноценный объект в куче. Если вы снова напишете:

String str3 = "abc"; 

Он больше не будет создавать объект в пуле, он проверит пул, если этот литерал уже существует, и назначит его ему. Но писать:

String str4 = new String("abc");

снова создаст новый объект в куче

Ключевым моментом является то, что:

Новый объект всегда будет создаваться в куче столько раз, сколько вы будете писать:

new String("abc");

Но если вы продолжаете назначать строки напрямую, не используя ключевое слово new, на них просто ссылаются из пула памяти (или создают, если они отсутствуют в пуле памяти)

Метод intern() определяет, присутствует ли строка в пуле памяти, если нет, то добавляет ее в пул памяти и возвращает ссылку на нее. поэтому после использования этого метода ваша ссылка на строку не указывает ни на какой объект в куче, она указывает на объект в пуле строковой памяти (также обратите внимание, что пул памяти содержит только уникальные строки).

person Sarthak Mittal    schedule 30.11.2014
comment
Начиная с jdk 7 и 8, интернированные объекты String также хранятся в куче. java-performance.info/string-intern-in-java -6-7-8 - person nanosoft; 24.06.2015
comment
Как насчет того, чтобы new String(test).intern() поместил объект, если он еще не существует? А что, если 1. литерал уже в пуле или 2. уже в куче? - person xploreraj; 27.09.2015
comment
@xploreraj проверьте документы java API для intern (), его цель четко указана. - person Sarthak Mittal; 01.10.2015

Когда вы говорите new String(), вы получаете новую ссылку Object, так что подумайте

String a = "text";
String b = new String("text");
System.out.println(a == b);
b = b.intern();
System.out.println(a == b);

Тогда сначала a == b будет отображаться false, потому что это разные ссылки. Если мы intern() b скажем b = b.intern(), мы можем снова проверить и получить true. Надеюсь, это поможет. Приведенный выше код работает одинаково в Java, начиная с версии 1.0 (и до сих пор работает в Java 8).

person Elliott Frisch    schedule 30.11.2014
comment
Спасибо за быстрый ответ, Эллиотт. Я понимаю, что оба вышеуказанных условия дают true. Я думаю, чтобы быть более точным, меня смущает следующее: становятся ли строковые значения, указанные в пуле констант (который мне удалось прочитать с помощью команды javap -c -verbose ClassName.class в cmd) + загружается во внутренний пул, который, начиная с Java 7, находится в куче? Является ли постоянный пул реальной сущностью во время выполнения? (Извините, если мой вопрос сбивает с толку, если необходимы разъяснения, дайте мне знать) - person kylemart; 30.11.2014
comment
@KyleMart Первый дает false. Попытайся. Я пытаюсь объяснить, как работает пул intern(). - person Elliott Frisch; 30.11.2014
comment
Виноват. Ржу не могу. Я действительно хотел сказать, что первое из двух условий будет ложным. Совершенно сумасшедший, когда писал мой последний комментарий. Причина, по которой 1-е условие равно false, заключается в том, что var a ссылается на строку во внутреннем пуле, а var b ссылается на строку в куче, верно? Меня смущает взаимосвязь между внутренним пулом и постоянным пулом. - person kylemart; 30.11.2014
comment
@KyleMart рассмотреть System.out.println(new Integer(1024) == Integer.valueOf(1024)); - person Elliott Frisch; 30.11.2014
comment
Это было бы неверно, верно? Левый операнд создает новый целочисленный объект, а правый метод valueOf создает новый целочисленный объект со значением 1024, кэширует его и возвращает ссылку на кэшированный объект. - person kylemart; 30.11.2014
comment
@KyleMart Правильно. Урок, который вы должны усвоить, состоит в том, чтобы использовать .equals() и попытаться написать Тупой код. Кроме того, когда вы используете new, вы создаете ссылку. - person Elliott Frisch; 30.11.2014
comment
Является ли String#intern родным кодом или в классе String есть реализация Java?\ - person nanofarad; 30.11.2014
comment
Приведенный выше код печатает false и true во всех текущих реализациях, без вопросов. Но гарантирует ли спецификация JVM гарантию, что строка, созданная с помощью new String(…), никогда не будет автоматически интернирована? Итак, гарантируется ли, что сравнение == любого объекта String с new String(…) всегда будет возвращать false? - person ujay68; 06.03.2015
comment
@ ujay68: оператор new гарантированно создаст новый экземпляр объекта с уникальным идентификатором. Таким образом, сравнение ссылок всегда будет возвращать false, если можно исключить, что второй объект — это тот, который вы только что создали. Например, если вы вызовете intern() для нового экземпляра строки или передадите его какому-то неизвестному коду, который мог бы это сделать, ваши ставки отменяются… - person Holger; 02.05.2016