Меня смущает StringPool в Java. Я наткнулся на это, читая главу о строках в Java. Пожалуйста, помогите мне понять, с точки зрения непрофессионала, что на самом деле делает StringPool.
Переведено автоматически
Ответ 1
Это выводит true (хотя мы не используем equals метод: правильный способ сравнения строк)
Когда компилятор оптимизирует ваши строковые литералы, он видит, что оба s и t имеют одинаковое значение, и, следовательно, вам нужен только один строковый объект. Это безопасно, потому что String является неизменяемым в Java.
В результате оба s и t указывают на один и тот же объект и экономят немного памяти.
Название "пул строк" происходит от идеи, что все уже определенные строки хранятся в некотором "пуле", и перед созданием нового String объекта компилятор проверяет, определена ли такая строка.
Ответ 2
Я не думаю, что это на самом деле много значит, похоже, что это просто кэш для строковых литералов. Если у вас есть несколько строк, значения которых одинаковы, все они будут указывать на один и тот же строковый литерал в пуле строк.
Давайте начнем с цитаты из спецификации виртуальной машины:
Загрузка класса или интерфейса, содержащего строковый литерал, может создать новый строковый объект (§2.4.8) для представления этого литерала. Этого может не произойти, если объект a String уже был создан для представления предыдущего вхождения этого литерала, или если метод String.intern был вызван для объекта String, представляющего ту же строку, что и литерал.
Этого может и не произойти - Это намек на то, что в String объектах есть что-то особенное. Обычно вызов конструктора всегда создает новый экземпляр класса. Это не относится к строкам, особенно когда строковые объекты "создаются" с помощью литералов. Эти строки хранятся в глобальном хранилище (пуле) - или, по крайней мере, ссылки хранятся в пуле, и всякий раз, когда требуется новый экземпляр уже известных строк, виртуальная машина возвращает ссылку на объект из пула. В псевдокоде это может выглядеть следующим образом:
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 := newString("one")
Опять же, "one" создается в пуле, но затем мы создаем новый экземпляр из того же литерала, и в этом случае это приводит к (a == b) && (a.equals(b)) == false
Итак, почему у нас есть пул строк? Строки и особенно строковые литералы широко используются в типичном коде Java. И они неизменяемы. И будучи неизменяемым, позволяет кэшировать строку для экономии памяти и повышения производительности (меньше усилий на создание, меньше мусора, который нужно собирать).
Как программистам нам не нужно особо заботиться о пуле строк, пока мы помним:
(a == b) && (a.equals(b)) может быть true или false (всегда используйте equals для сравнения строк)
Не используйте отражение для изменения резервной копии char[] строки (поскольку вы не знаете, кто на самом деле использует эту строку)
Ответ 4
Когда JVM загружает классы или иным образом видит литеральную строку или некоторый кодintern, являющийся строкой, он добавляет строку в в основном скрытую таблицу поиска, которая содержит одну копию каждой такой строки. Если добавляется еще одна копия, среда выполнения упорядочивает ее так, чтобы все литералы ссылались на один и тот же объект string . Это называется "интернированием". Если вы скажете что-то вроде
Strings="test"; return (s == "test");
он вернет true, потому что первый и второй "тест" на самом деле являются одним и тем же объектом. Сравнение интернированных строк таким способом может быть намного, намного быстрее, чем String.equals, поскольку используется одно ссылочное сравнение, а не куча char сравнений.
Вы можете добавить строку в пул, вызвав String.intern() , который вернет вам объединенную версию строки (которая может быть той же самой строкой, которую вы интернируете, но было бы безумием полагаться на это - вы часто не можете быть уверены, какой именно код был загружен и запущен до сих пор, и интернировал ту же самую строку). Объединенная версия (строка, возвращаемая из intern) будет равна любому идентичному литералу. Например:
Strings1="test"; Strings2=newString("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"