2009-12-10 4 views
63

Рассмотрим этого кода:Вопросов о Струнной пуле в Java

String first = "abc"; 
String second = new String("abc"); 

При использовании new ключевого слова, Java будет создать abcString снова правильно? Будет ли это храниться на обычной куче или в бассейне String? Сколько String s закончится в бассейне String?

+0

@dmindreader: Я не уверен, что вы хотите использовать для этого ... но это напоминает мне то, что я прочитал раньше, и отправил в качестве ответа на другой вопрос SO. Пожалуйста, прочитайте мой ответ на другой вопрос, поскольку он подчеркивает, что использование этих деталей реализации может быть хрупким: http://stackoverflow.com/questions/1111296/when-s-is-false-but-equals-s-is-true/1111405 # 1111405 – Tom

+1

Да, куча и 1. –

ответ

90

Если вы используете ключевое слово new, будет создан новый объект String. Обратите внимание, что объекты всегда находятся в куче - пул строк не является отдельной областью памяти, которая отделена от кучи.

Пул строк подобен кешу. Если вы сделаете это:

String s = "abc"; 
String p = "abc"; 

то компилятор Java достаточно умен, чтобы сделать только один String объекта и s и p оба будут со ссылкой на тот же объект String. Если вы сделаете это:

String s = new String("abc"); 

тогда будет один String объект в бассейне, то один, который представляет буквальный "abc", и там будет отдельный String объект, а не в бассейне, который содержит копию содержимое объединенного объекта. Поскольку String неизменен на Java, вы ничего не набираете, делая это; вызов new String("literal") никогда не имеет смысла в Java и излишне неэффективен.

Заметь, что вы можете позвонить по телефону intern() по объекту String. Это положит объект String в пул, если он еще не существует и возвращает ссылку на пустую строку. (Если он уже был в пуле, он просто возвращает ссылку на объект, который уже был там). Дополнительную информацию см. В документации по API для этого метода.

См. Также String interning (Википедия).

+0

Предположительно, это основано на шаблоне проектирования Fly-weight. –

+0

@Wim: Да, это, по сути, мухи. – Jesper

+0

Пул intern() всегда находится в куче; Я полагаю, что вопрос задает вопрос о пуле ** констант классов ** – dfa

11

В байткодом, первое задание:

 
    Code: 
    0: ldc  #2; //String abc 
    2: astore_1 

в то время как вторая:

 
    3: new  #3; //class java/lang/String 
    6: dup 
    7: ldc  #2; //String abc 
    9: invokespecial #4; //Method java/lang/String."":(Ljava/lang/String;)V 

Таким образом, первый находится в бассейне (в положении # 2), тогда как второй будет храниться в куче.

РЕДАКТИРОВАТЬ

С CONSTANT_String_infostore the index as U2 (16 бит, без знака) пул может содержать при макс 2**16 = 65535 ссылки. В случае, если вы беспокоитесь here more limits of the JVM.

+2

Глядя на байт-код - это хороший (и пропущенный) способ узнать, что именно делает программа. – Jesper

+0

Как вы смотрите на байт-код? Что вы использовали для доступа к нему? – andandandand

+0

javap, утилита, распространяемая в jdk солнца http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/javap.html – dfa

7

Каждый раз, когда ваш код создает строковый литерал

, например:

String str="Hello"; (string literal) 

виртуальная машина проверяет строку буквального бассейн первым.Если строка уже существует в пуле, возвращается ссылка на объединенный экземпляр. Если строка не существует в пуле, создается новый объект String, а затем помещается в пул. Java может сделать эту оптимизацию, поскольку строки являются неизменными и могут использоваться совместно, не опасаясь повреждения данных.

+1

Не эта проверка выполняется компилятором java, а не JVM? – rds

+0

[Этот ответ на тот же вопрос] (http://stackoverflow.com/a/1881936/507738) гласит, что это правильно. –

2

Единственный раз, когда вы должны использовать новую String (foo), это когда вы хотите разбить ==, что является нечетным случаем, или когда Foo подстрока гораздо большей строки, которая имеет ограниченный срок службы, такие как

String mystring; 
{ 
    String source = getSomeHeinouslyLargeString(); 
    mystring = new String(source.substring(1,3)); 
} 
3
String strObject = new String("Java"); 

и

String strLiteral = "Java"; 

Оба выражения дает объект String, но есть тонкая разница между ними. Когда вы создаете объект String с помощью new(), он всегда создает новый объект в кучевой памяти. С другой стороны, если вы создаете объект, используя синтаксис строкового литерала, например. «Java», он может вернуть существующий объект из пула String (кеш объекта String в пространстве Perm gen, который теперь перемещается в кучу пространства в последнем выпуске Java), если он уже существует.

+2

вы взяли текст avoe из (Разница между строковым литералом и объектом New String в Java) [http://java67.blogspot.com/2014/08/difference-between-string-literal-and-new-String-object- Java.html # ixzz3t59ORyBW ] Полезно упомянуть ссылку, с которой вы взяли данные. – Dev

+0

Это * будет * возвращать объект из пула строк, если это буквальный. «Нет». – EJP

0

Хотя поздно, может быть полезным для кого-то еще прийти через это:

String first = "abc"; 
//One instance object in pool created. Instance variable “first” refers/points to pooled object 

String second = new String("abc");  
//One instance object in heap created. Object in pool creation step will be skipped on account of first statement. 

Таким образом, в общей сложности 2 объектов экземпляра будет создан. Один в бассейне и другие в куче

Подробное объяснение

Строка первый = "ABC";

Здесь строковый объект с содержимым «abc», созданный в пуле. Переменная экземпляра «first» будет указывать на объект пула с содержимым «abc».

Строка second = new String ("abc");

Здесь в куче будет создан другой строковый объект с контентом «abc». Переменная «second» экземпляра будет указывать на объект кучи с содержимым «abc». Строковый объект с созданием содержимого «abc» в пуле будет пропущен из-за 1-го утверждения. Причина ниже.

Причины

Если предполагаются до утверждения (String первого = «ABC»;) не существует с таким же содержанием, то вообще с «новым» ключевым словом, 2 строковых объекты будут создаваться один в куче (вне пул), а другой в пуле (область подсетей кучи). Также переменная экземпляра «вторая» должна указывать только на объект кучи, независимо от того, находятся ли объекты в пуле или нет.

Теперь из-за наличия предыдущего оператора (String first = "abc";) с тем же содержимым, что и в новой строке ("abc"), только один объект (с содержимым «abc») сохраняется в пуле. Так что из-за 1-го утверждения второй оператор будет иметь только один объект, созданный вместо 2, и этот объект находится в куче. Создание объекта пула будет пропущено.

//Additional Test on the concept 
System.out.println(first==second); //returns false. Because first points to pool object while second points to heap object. And both objects are different (on account of different memory locations). 

second = second.intern();   //After interning, second now points to pool object. Note: intern is used so that reference variable points to pool area object and not heap object. Clearly it is applicable when we use new keyword. 

System.out.println(first==second); //returns true. Because now both first and second objects now points to same pool object. 
0
String first = "abc"; 
String second = new String("abc"); 

В первом случае есть только один объект будет создан в бассейн. Во втором случае два объекта будут создавать один в пуле (если он ранее не был в пуле) и один в куче.

Когда вы передаете любое значение с двойной цитатой ex: «abc», вы создаете объект в пуле и передаете его в конструктор строк для создания нового объекта с тем же значением в куче.

Если вы видели конструктор строк, вы можете видеть, что он принимает строку. Что это за строка? Перед созданием этого строкового объекта. Это ничего, кроме объекта, хранящегося в пуле String Constant.