Что такое пул строк в Java?
Я запутался в StringPool в Java. Я натолкнулся на это, читая главу String на Java. Пожалуйста, помогите мне понять, на простых условиях, что на самом деле делает StringPool.
- Какую оптимизацию я могу ожидать от Dalvik и инструментальной цепочки Android?
- Можно использовать два classа Java с одинаковым именем и одним пакетом?
- Как установить выбранный элемент Spinner по значению, а не положением?
- Записывать телефонные звонки на Android-телефоне?
- Как дождаться завершения всех задач в ThreadPoolExecutor, не закрывая Executor?
- Как удалить простыню вокруг кнопок в Android?
- Design lib - CoordinatorLayout / CollapsingToolbarLayout с GridView / listView
- Android - ImageLoader должен быть init с настройкой перед использованием в UIL
Это выводит 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.
Начнем с цитаты из спецификации виртуальной машины:
Загрузка classа или интерфейса, который содержит строковый литерал, может создать новый объект String (§2.4.8) для представления этого литерала. Это может не произойти, если объект String уже создан для представления предыдущего вхождения этого литерала или если метод String.intern был вызван на объект String, представляющий ту же строку, что и литерал.
Это может не произойти – это намек на то, что есть что-то особенное в объектах String
. Обычно вызов конструктора всегда создает новый экземпляр classа. Это не относится к строкам, особенно когда объекты 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
для сравнения строк) - Не использовать reflection , чтобы изменить защитный
char[]
из строки (как вы не знаете , кто actualling с помощью этой строки)
Когда JVM загружает classы или иным образом видит литеральную строку или некоторую строку кода sa sa sa, она добавляет строку в почти скрытую таблицу поиска, которая имеет одну копию каждой такой строки. Если добавлена другая копия, среда выполнения упорядочивает ее так, чтобы все литералы ссылались на один и тот же строковый объект. Это называется «интернированием». Если вы скажете что-то вроде
String s = "test"; return (s == "test");
он вернет true
, потому что первый и второй «тест» на самом деле являются одним и тем же объектом. Сравнение интернированных строк таким образом может быть намного, намного быстрее, чем String.equals
, так как существует только одно сравнительное сравнение, а не сравнение 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"