Возврат String.intern() объяснил
Рассматривать:
String s1 = new StringBuilder("Cattie").append(" & Doggie").toString();
System.out.println(s1.intern() == s1); // true why?
System.out.println(s1 == "Cattie & Doggie"); // true another why?
String s2 = new StringBuilder("ja").append("va").toString();
System.out.println(s2.intern() == s2); // false
String s3 = new String("Cattie & Doggie");
System.out.println(s3.intern() == s3); // false
System.out.println(s3 == "Cattie & Doggie"); // false
Я запутался, почему они получаются по-разному из-за возвращенного значения String.intern()
которое говорит:
Когда вызывается метод intern, если пул уже содержит строку, равную этому объекту String, как определено методом equals (Object), возвращается строка из пула. В противном случае этот объект String добавляется в пул и возвращается ссылка на этот объект String.
Особенно после этих двух испытаний:
assertFalse("new String() should create a new instance", new String("jav") == "jav");
assertFalse("new StringBuilder() should create a new instance",
new StringBuilder("jav").toString() == "jav");
Однажды я прочитал пост, рассказывающий о некоторых special strings
интернированных до всего остального, но сейчас это настоящее размытие.
Если есть какие-то строки pre-interned
, есть ли способ получить вид их списка? Мне просто интересно, что они могут быть.
обновленный
Благодаря помощи @Eran и @Slaw, я наконец могу объяснить, что только что произошло там для вывода
true
true
false
false
false
- Поскольку
"Cattie & Doggie"
не существует в пуле, s1.intern() поместит текущую ссылку на объект в пул и вернет себя, поэтому s1.intern() == s1
; -
"Cattie & Doggie"
уже находится в пуле, поэтому строковый литерал "Cattie & Doggie"
будет просто использовать ссылку в пуле, которая на самом деле является s1
, поэтому мы снова имеем true
; -
new StringBuilder().toString()
создаст новый экземпляр, пока "java"
уже находится в пуле, и тогда ссылка на пул будет возвращена при вызове s2.intern()
, поэтому s2.intern() != s2
и мы иметь false
; -
new String()
также возвратит новый экземпляр, но когда мы попытаемся выполнить s3.intern()
, он вернет ранее сохраненную ссылку в пуле, которая на самом деле является s1
поэтому s3.intern() != s3
и мы имеем false
; - Как уже обсуждалось # 2, строковый литерал
"Cattie & Doggie"
вернет ссылку, уже сохраненную в пуле (которая на самом деле является s1
), поэтому s3 != "Cattie & Doggie"
и мы снова получим false
.
Спасибо @Sunny за трюк, чтобы получить все interned
строки.
Ответы
Ответ 1
s2.intern()
вернет экземпляр, на который ссылается s2
только если пул строк не содержит String
, значение которой равно "java" до этого вызова. Классы JDK интернируют некоторую String
до того, как ваш код будет выполнен. "Ява" должно быть одним из них. Поэтому s2.intern()
возвращает ранее интернированный экземпляр вместо s2
.
С другой стороны, классы JDK не интернировали ни одну String
, значение которой равно "Cattie & Doggie", поэтому s1.intern()
возвращает s1
.
Я не знаю ни одного списка предварительно интернированных строк. Такой список, скорее всего, будет считаться деталями реализации, которые могут различаться в разных реализациях JDK и версиях JDK, и на них нельзя полагаться.
Ответ 2
Когда метод intern() вызывается для объекта String, он ищет строку, содержащуюся в этом объекте String, в пуле, если строка находится там, возвращается строка из пула. В противном случае этот объект String добавляется в пул и возвращается ссылка на этот объект String.
Так что java
строка уже должна быть в пуле. следовательно, это дает ложь.
Вы можете распечатать все строки в бассейне
Как распечатать весь пул строк?
Вот пример, чтобы получить всю строку, если вы используете openjdk.
Ответ 3
Строковые литералы (те, которые жестко закодированы как "строка") уже интернированы для вас компилятором. Но те строки, которые получены программно, не являются и будут интернированы, только если вы используете .intern()
.
Обычно вы не интернируете строки вручную, если вы не знаете, что будете хранить в памяти большое количество повторяющихся строк, так что вы можете сэкономить много памяти таким образом.
Это объясняется здесь: что такое интернирование Java String?