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

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

4 ответа

Решение

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

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

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

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

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

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

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

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

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

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. И они неизменны. И неизменность позволила кэшировать String для экономии памяти и увеличения производительности (меньше усилий для создания, меньше мусора для сбора).

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

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

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

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"
Другие вопросы по тегам