Вопросы о пуле 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.