Возврат String.intern () объяснил - PullRequest
20 голосов
/ 13 марта 2019

Рассмотрим:

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
  1. Поскольку "Cattie & Doggie" не существует в пуле, s1.intern () поместит текущую ссылку на объект в пул и вернет себя, поэтому s1.intern() == s1;
  2. "Cattie & Doggie" уже в пуле, поэтому строковый литерал "Cattie & Doggie" будет просто использовать ссылку в пуле, которая на самом деле s1, так что мы снова имеем true;
  3. new StringBuilder().toString() создаст новый экземпляр, пока "java" уже находится в пуле, и тогда ссылка на пул будет возвращена при вызове s2.intern(), поэтому s2.intern() != s2 и у нас false;
  4. new String() также вернет новый экземпляр, но когда мы попытаемся s3.intern(), он вернет ранее сохраненную ссылку в пуле, которая на самом деле s1, поэтому s3.intern() != s3, и у нас будет false;
  5. Как уже обсуждалось # 2, строковый литерал "Cattie & Doggie" вернет ссылку, уже сохраненную в пуле (которая на самом деле s1), поэтому s3 != "Cattie & Doggie" и мы снова получим false.

Спасибо, что @Sunny предоставил трюк для получения всех interned строк.

Ответы [ 3 ]

28 голосов
/ 13 марта 2019

s2.intern() вернет экземпляр, на который ссылается s2, только если пул строк не содержит String, значение которого равно "java" до этого вызова.Классы JDK стажируются за String с до того, как ваш код будет выполнен."Ява" должно быть одним из них.Поэтому s2.intern() возвращает ранее интернированный экземпляр вместо s2.

С другой стороны, классы JDK не интернировали ни одного String, значение которого равно "Cattie & Doggie", поэтому s1.intern() возвращает s1.

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

3 голосов
/ 13 марта 2019

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

Таким образом, строка java должна уже находиться в пуле.следовательно, это дает ложь.

Вы можете напечатать все строки в пуле

Как напечатать весь пул строк?

Вот это пример , чтобы получить всю строку, если вы используете openjdk .

0 голосов
/ 13 марта 2019

Строковые литералы (те, которые жестко закодированы как "строка") уже интернированы для вас компилятором.Но те строки, которые получены программно, не являются и будут интернированы, только если вы используете метод .intern().

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

Это объясняется здесь: Что такое интернирование Java String?

...