Серия вопросов интервью Часть 6: Подробнее о пуле констант строк JVM и методе стажировки String?

«Серия вопросов для собеседований по Java»: обширная и очень интересная колонка. Углубленное копание, анализ исходного кода, обобщение принципов, объединение картинок и текстов, создание серии статей в официальном аккаунте и повышение уровня для интервью или нет Добро пожаловать, чтобы продолжать обращать внимание на [Program New Vision]. Это шестая глава.

Сравнение строк было подробно объяснено в предыдущей статье.В этой статье дается пошаговое объяснение, основанное на хранении пула строковых констант и изменениях памяти, вызванных при использовании метода intern.

Ключевое содержание: какие изменения произойдут, когда строка вызывает метод intern, а затем сравнивает строки?

Содержание этой статьи объясняется на основе виртуальной машины HotSpot.

Вопросы на собеседовании

Давайте сначала разберемся с формой представления контента, о котором мы собираемся поговорить в этой статье, через изображение вопроса для интервью:

String s1 = new String("he") + new String("llo");
String s2 = new String("h") + new String("ello");

String s3 = s1.intern();
String s4 = s2.intern();
System.out.println(s1 == s3);
System.out.println(s1 == s4);

Выполните приведенный выше код, и вы обнаружите, что все напечатанные результаты верны. Итак, почему строки не равны до того, как стали равными после вызова метода intern? Давайте шаг за шагом проанализируем базовую реализацию.

Роль метода стажера

Определение функции метода intern ():

(1) Если текущее строковое содержимое существует в пуле строковых констант (то есть метод equals () истинен, то есть содержимое такое же), тогда непосредственно вернуть ссылку на эту строку в константном пуле;

(2) Если текущая строка не находится в пуле констант строк, создайте ссылку в пуле констант и укажите строку, которая уже существует в куче, а затем верните ссылку в пуле констант.

Проще говоря, метод intern должен определить, существует ли строка в пуле строковых констант, создать ее, если она не существует, и вернуть ее, если она существует.

Пул констант строк

Функция пула строковых констант в HotSpot реализует класс StringTable, который представляет собой хеш-таблицу со значением по умолчанию 1009. В каждом экземпляре виртуальной машины HotSpot есть только одна копия, которая используется всеми классами. Строковые константы состоят из символов и помещаются в StringTable.

В серии вопросов интервью № 5: пул констант времени выполнения JDK, пул строковых констант, пул статических констант, все еще глуп и запутан? «В этой статье мы специально представили расположение изменений пула строковых констант в версии JDK, вы можете обратиться к нему.

В JDK6 и более ранних версиях пул строковых констант помещается в область Perm Gen (область методов). Длина StringTable является фиксированной, а длина равна 1009. Когда строк слишком много, могут возникать конфликты хэшей, что приводит к чрезмерно длинному связанному списку и значительному снижению производительности. В это время все строковые константы (буквальные значения) помещаются в пул строковых констант.

Из-за ограниченного и фиксированного пространства постоянного поколения режим хранения JDK6 может легко вызвать OutOfMemoryError.

А JDK7 работал над постоянной генерацией, поэтому пул строковых констант был помещен в кучу. В настоящее время, даже если размер кучи является фиксированным, для настройки приложения необходимо настроить только размер кучи.

В JDK7 пул строковых констант может не только хранить строковые константы, но также хранить строковые ссылки. Другими словами, ссылка на строку в куче может существовать как значение пула констант.

Анализ процесса объединения строк

После понимания изложенной выше базовой теории мы шаг за шагом продемонстрируем процесс и классификацию объединения строк в виде комбинации изображений и текста. Следующие примеры анализируются и объясняются на основе версии JDK8.

Когда мы объявляем строку в двойных кавычках:

String wechat = "程序新视界";

В это время строка в двойных кавычках будет напрямую сохранена в пуле строковых констант.
Вставьте описание изображения сюда

Что касается вышеуказанной структуры хранилища, мы уже упоминали ее в предыдущей статье и не будем подробно ее объяснять. Затем, если мы снова объявим ту же строку, чтобы увидеть, какие изменения произойдут.

String wechat = "程序新视界";
String wechat1 = "程序新视界";

Когда wechat1 объявлен в приведенном выше коде, будет обнаружено, что соответствующая строка уже существует в пуле констант, она не будет воссоздана, но соответствующая ссылка будет возвращена в wechat1. Соответствующая структурная схема выглядит следующим образом:
Вставьте описание изображения сюда

На этом этапе, если вы напрямую сравниваете wechat и wechat1 с двойным знаком равенства, они определенно равны, потому что их ссылки и буквальные значения одинаковы.

Вышеупомянутое является случаем прямого присвоения двойных кавычек, так как же происходит процесс создания строки в форме new? В предыдущей статье говорилось об этих двух ситуациях: в пуле констант есть соответствующее значение, а соответствующего значения нет.

String wechat2 = new String("程序新视界");

Если есть соответствующее значение, то сначала в куче будет создана ссылка на объект переменной wechat2, а затем ссылка на объект будет указывать на константу, которая уже существует в пуле строковых констант.
Вставьте описание изображения сюда

В настоящее время прямое использование двойного знака равенства для сравнения переменных wechat и wechat2 определенно не равно, в то время как буквальное значение сравнения с помощью метода equals равно.

Другая ситуация заключается в том, что при создании с помощью new в пуле строковых констант нет соответствующей константы. В этом случае строковая константа создается в пуле строковых констант, а затем в куче создается строка, содержащая ссылку на соответствующую строку в пуле констант. И верните адрес объекта в куче в wechat2. Окончательный рендеринг такой же, как показано выше.

В настоящее время, если вы не назначаете новую строку напрямую, а используете знак +, ситуация иная.

String s1 = "程序";
String wechat3 = new String(s1 + "新视界");

Приведенный выше код s1 будет храниться в пуле констант, а значение wechat3 будет создавать только объект String в куче и не будет сохранять соответствующую строку в пуле констант, потому что StringBuilder используется для объединения знака плюс при компиляции JVM.
Вставьте описание изображения сюда

Ситуация на этот раз уже вовлекла создание строк в наших вопросах интервью. Итак, давайте воспользуемся методом intern для выполнения операций объединения, чтобы увидеть конкретные изменения в пуле строковых констант.

В качестве примера возьмем приведенный выше код.В настоящее время три переменные wechat, wechat1, wechat2 и wechat3 определенно не равны по сравнению с двойным знаком равенства. Затем wechat3 будет объединен в пул стажеров.

String s1 = "程序";
String wechat3 = new String(s1 + "新视界");
wechat3 = wechat3.intern();

Вы обнаружите, что значения wechat и wechat1 равны значениям wechat3. Поскольку wechat и wechat1 на самом деле являются одним целым, здесь мы берем сравнение wechat и wechat3 только в качестве примера для анализа этого процесса.

Состояние памяти до вызова метода intern показано на рисунке ниже (без учета части s1):

образ

Неудивительно, что их значения не равны на картинке выше. Затем мы объединяем wechat3 и присваиваем результат объединения wechat3, как показано выше. Структура памяти изменится следующим образом:
Вставьте описание изображения сюда

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

Тогда возникает другая ситуация, а именно, как соответствующее значение не будет существовать в пуле констант? Сначала посмотрите на следующий код:

String s2 = "关注";
String wechat4 = new String(s2 + "公众号");
wechat4 = wechat4.intern();

Операция перед вызовом intern. Мы уже говорили, что объект String будет создан в куче, а его копия не будет храниться в пуле констант, как и граф в wechat3.

В настоящее время в пуле констант нет соответствующей строки. В настоящее время после вызова метода intern структура памяти выглядит следующим образом:
Вставьте описание изображения сюда

После метода intern ссылка на соответствующую строку в куче сохраняется в пуле констант. В отличие от вышесказанного, пулы строковых констант JDK7 и более поздних версий могут хранить ссылки.

Следует отметить, что когда соответствующая строка не существует в пуле строковых констант, адрес, возвращаемый при вызове метода intern, является адресом в куче, соответствующим 0x99 на рисунке. Исходный адрес wechat4 указывает на адрес в куче, поэтому он не изменится.

В настоящее время, если вы определяете wechat5, назначенное двойными кавычками, следующий код:

String s2 = "关注";
String wechat4 = new String(s2 + "公众号");
wechat4 = wechat4.intern();

String wechat5 = "关注公众号";
System.out.println(wechat4 == wechat5);

Когда переменная wechat5 инициализируется, обнаруживается, что есть ссылка в пуле строковых констант, тогда wechat5 будет напрямую указывать на эту ссылку, то есть wechat5 и wechat4 оба указывают на объект String в памяти.
образ

резюме

Ключевым моментом, который следует отметить в приведенной выше демонстрации, является ссылочный адрес, возвращаемый методом intern. Если соответствующая строка уже существует в пуле строковых констант, в это время возвращается адрес строковой константы [строка хранится в пуле констант]. Если соответствующая строка не существует в пуле строковых констант, тогда Ссылка в куче будет помещена в соответствующую позицию пула констант [пул констант хранит ссылку на строку в куче], в это время intern возвращает ссылку, соответствующую строке в куче.

После пояснения приведенной выше логики возврата посмотрите на исходный код:

String s1 = new String("he") + new String("llo");
String s2 = new String("h") + new String("ello");

String s3 = s1.intern();
String s4 = s2.intern();
System.out.println(s1 == s3);
System.out.println(s1 == s4);

Где s1 - адрес строки «hello» в куче; s2 - адрес другой строки «hello» в куче. Когда s1.intern (), адрес s1 сохраняется в пуле констант. В это время s1.intern () возвращает адрес s1, поэтому s1 = s3, это тот же адрес.

Затем выполните s2.intern (). В это время в пуле констант уже есть строка приветствия. Тип является ссылкой и указывает на адрес s1. После выполнения возвращается адрес s1, который присваивается s4, поэтому s1 и s4 также указывают на одно и то же Следовательно, адреса равны.

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

Исходная ссылка: « Интервью, часть 6: подробный пул констант строк JVM и метод стажировки String?

Справочная статья:

https://www.zhihu.com/question/55994121


Новое видение процедуры

Публичный аккаунт « Новое видение программы », платформа, которая позволяет вам одновременно улучшать вашу мягкую силу и жесткие технологии, предоставляя огромные объемы данных

Официальный аккаунт WeChat: новое видение программы

рекомендация

отblog.csdn.net/wo541075754/article/details/108374856