Как работает интерпретация строк в 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 сегодня).