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

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

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

В приведенном выше примере я понимаю, что будут созданы два объекта String. Я также понимаю, что будет только один массив char, содержащий последовательность "t", "e", "x" и "t" в памяти. Однако, где в памяти хранятся каждый из объектов строки? Если то, что я прочитал, я прочитал правильно: референт переменной a будет сохранен в пуле констант, тогда как референт b будет сохранен в куче, верно? Если это так, я смущен тем, как внутренний пул поддерживает интернированные строки. Он отслеживает строки, определенные в пуле констант, и те, которые были вручную интернализованы (вызывается .intern()) из кучи? Создает ли JVM строковые объекты, определенные в пуле констант, и загружает их в главный пул? Я смущен тем, как все это работает...

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

Ответы

Ответ 1

В 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() находит, если строка присутствует в пуле памяти, если она не добавляет его в пул памяти и возвращает ссылку на него. поэтому после использования этого метода ссылка String вашего не указывает на какой-либо объект в куче, он указывает на объект в пуле строк String (также обратите внимание, что пул памяти содержит только уникальные строки)

Ответ 2

Когда вы скажете 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 сегодня).