Является ли String Pool действительно пустым изначально, как упомянуто в методе Javadoc метода String.intern ()? - PullRequest
0 голосов
/ 24 апреля 2018

Ниже приведен комментарий Javadoc для метода String.intern ():

* Возвращает каноническое представление для строкового объекта.

Пул строк, изначально пустой , поддерживается в частном порядке классом String.

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

Отсюда следует, что для любых двух строк s и t s.intern () == t.intern () имеет значение true, если и только если s.equals (t) имеет значение true.

Все литеральные строки и строковые константные выражения интернированы. Строковые литералы определены в разделе 3.10.5 Спецификации языка Java ™. ”

Но я думаю, что что-то изменило jdk-8u102 вперед.

Проверьте ниже пример:

public class Test1 {
    public static void main(String[] args) {
        String s1 = new String(new char[]{'J', 'a', 'v', 'a'});
        String s2 = s1.intern(); 
        System.out.println(s1 == s2);
    }
}

Если вы запустите вышеуказанную программу в JDK 7u80 (последняя стабильная версия JDK 7) и JDK 8 до 8u101, то вы получите:
true

Но если вы запустите вышеуказанную программу в JDK 8u102 и далее в JDK 9 и JDK 10, то вы получите:
false

Почему метод intern () начал работать по-разному в JDK 8u102 и далее?

Я проверил примечания к выпуску и комментарии Javadoc, но не смог найти ничего об изменениях, связанных с методом intern () в JDK 8u102.

Я проверил блоги и другие сайты, но не повезло.

Но когда я попытался с какой-то другой строкой, в выводе не было никаких изменений:

public class Test2 {
    public static void main(String[] args) {
        String s3 = new String(new char[]{'U', 'd', 'a', 'y', 'a', 'n'});
        String s4 = s3.intern();
        System.out.println(s3 == s4);
    }
}

Приведенная выше программа всегда печатает true в JDK 7, JDK 8, JDK 9 и JDK 10.

Такое поведение возможно только в том случае, если перед загрузкой класса Test1 таблица «Строка пула» указывает «Java».
s1 ссылается на объект String «Java» в HEAP, а s1.intern () возвращает ссылку на объект String Pool (поскольку «Java» уже упоминается в String Pool).
Вот почему s1 == s2 возвращает false.

Но когда загружен класс Test2, «Udayan» НЕ указывается в таблице пула строк.
s3 ссылается на объект String «Udayan» в HEAP, а s3.intern () добавляет объект String, на который ссылается s3, в String Pool и возвращает ту же ссылку. Это означает, что s3 и s4 относятся к одному и тому же объекту.
Вот почему s3 == s4 возвращает true.

Если мои наблюдения верны, то это означает, что пул строк НЕ пуст изначально.
Пул строк изначально содержит «Java», «java», «Oracle» и другие объекты String.

Может кто-нибудь подтвердить это?

1 Ответ

0 голосов
/ 24 апреля 2018

Это зависит от того, что вы считаете «изначально».

Когда JVM запускается, пул строк пуст. Однако, когда различные базовые классы JDK загружаются и инициализируются до загрузки класса Test1, неудивительно, что некоторые из них добавляют String s в пул строк. «Java» должен быть одним из этих String s.

И в JLS нет ничего, что мешало бы разработчикам Java вводить новые литералы String при инициализации классов в более новых версиях JDK. Поэтому разница, замеченная вами между JDK 7 и JDK 8, неудивительна.

...