Вопросы о пуле Java String

Рассмотрим этот код:

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

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

Ответ 1

Если вы используете ключевое слово 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 (Wikipedia).

Ответ 2

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

  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_info хранит индекс как U2 (16 бит, без знака), пул может содержать максимум 2**16= 65535 ссылки. В случае, если вам больше нравится здесь больше ограничений JVM.

Ответ 3

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

например:

String str="Hello"; (string literal) 

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

Ответ 4

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

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

Ответ 5

String strObject = new String("Java");

и

String strLiteral = "Java";

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

Ответ 6

Хотя и поздно, может быть полезно, когда кто-то все еще сталкивается с этим:

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 объекта экземпляра. Один в пуле и другой в куче

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

Строка first = "abc" ;

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

String second = new String ( "abc" );

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

Причины

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

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