Вопрос-ответ

What is String pool in Java? [duplicate]

Что такое пул строк в Java?

Меня смущает StringPool в Java. Я наткнулся на это, читая главу о строках в Java. Пожалуйста, помогите мне понять, с точки зрения непрофессионала, что на самом деле делает StringPool.

Переведено автоматически
Ответ 1

Это выводит true (хотя мы не используем equals метод: правильный способ сравнения строк)

    String s = "a" + "bc";
String t = "ab" + "c";
System.out.println(s == t);

Когда компилятор оптимизирует ваши строковые литералы, он видит, что оба s и t имеют одинаковое значение, и, следовательно, вам нужен только один строковый объект. Это безопасно, потому что String является неизменяемым в Java.

В результате оба s и t указывают на один и тот же объект и экономят немного памяти.

Название "пул строк" происходит от идеи, что все уже определенные строки хранятся в некотором "пуле", и перед созданием нового String объекта компилятор проверяет, определена ли такая строка.

Ответ 2

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

String s1 = "Arul"; //case 1 
String s2 = "Arul"; //case 2

В случае 1 литерал s1 создается заново и сохраняется в пуле. Но в случае 2 литерал s2 ссылается на s1, вместо него не будет создан новый.

if(s1 == s2) System.out.println("equal"); //Prints equal. 

String n1 = new String("Arul");
String n2 = new String("Arul");
if(n1 == n2) System.out.println("equal"); //No output.

http://p2p.wrox.com/java-espanol/29312-string-pooling.html

Ответ 3

Давайте начнем с цитаты из спецификации виртуальной машины:


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


Этого может и не произойти - Это намек на то, что в String объектах есть что-то особенное. Обычно вызов конструктора всегда создает новый экземпляр класса. Это не относится к строкам, особенно когда строковые объекты "создаются" с помощью литералов. Эти строки хранятся в глобальном хранилище (пуле) - или, по крайней мере, ссылки хранятся в пуле, и всякий раз, когда требуется новый экземпляр уже известных строк, виртуальная машина возвращает ссылку на объект из пула. В псевдокоде это может выглядеть следующим образом:

1: a := "one" 
--> if(pool[hash("one")] == null) // true
pool[hash("one") --> "one"]
return pool[hash("one")]

2: b := "one"
--> if(pool[hash("one")] == null) // false, "one" already in pool
pool[hash("one") --> "one"]
return pool[hash("one")]

Итак, в этом случае переменные a и b содержат ссылки на один и тот же объект. В этом случае мы имеем (a == b) && (a.equals(b)) == true.

Это не тот случай, если мы используем конструктор:

1: a := "one"
2: b := new String("one")

Опять же, "one" создается в пуле, но затем мы создаем новый экземпляр из того же литерала, и в этом случае это приводит к (a == b) && (a.equals(b)) == false

Итак, почему у нас есть пул строк? Строки и особенно строковые литералы широко используются в типичном коде Java. И они неизменяемы. И будучи неизменяемым, позволяет кэшировать строку для экономии памяти и повышения производительности (меньше усилий на создание, меньше мусора, который нужно собирать).

Как программистам нам не нужно особо заботиться о пуле строк, пока мы помним:


  • (a == b) && (a.equals(b)) может быть true или false (всегда используйте equals для сравнения строк)

  • Не используйте отражение для изменения резервной копии char[] строки (поскольку вы не знаете, кто на самом деле использует эту строку)

Ответ 4

Когда JVM загружает классы или иным образом видит литеральную строку или некоторый кодintern, являющийся строкой, он добавляет строку в в основном скрытую таблицу поиска, которая содержит одну копию каждой такой строки. Если добавляется еще одна копия, среда выполнения упорядочивает ее так, чтобы все литералы ссылались на один и тот же объект string . Это называется "интернированием". Если вы скажете что-то вроде

String s = "test";
return (s == "test");

он вернет true, потому что первый и второй "тест" на самом деле являются одним и тем же объектом. Сравнение интернированных строк таким способом может быть намного, намного быстрее, чем String.equals, поскольку используется одно ссылочное сравнение, а не куча char сравнений.

Вы можете добавить строку в пул, вызвав String.intern() , который вернет вам объединенную версию строки (которая может быть той же самой строкой, которую вы интернируете, но было бы безумием полагаться на это - вы часто не можете быть уверены, какой именно код был загружен и запущен до сих пор, и интернировал ту же самую строку). Объединенная версия (строка, возвращаемая из intern) будет равна любому идентичному литералу. Например:

String s1 = "test";
String s2 = new String("test"); // "new String" guarantees a different object

System.out.println(s1 == s2); // should print "false"

s2 = s2.intern();
System.out.println(s1 == s2); // should print "true"
java