опубликовано Нареш Джоши 17 февраля 2018 г.

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

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

Что ж, мы знаем, что String — самый популярный тип, представленный в Java, и почти все Java-программы используют его. На самом деле я не видел ни одной Java-программы, написанной без использования String. В общем, обычное бизнес-приложение Java имеет дело с тысячами строковых объектов, многие из них имеют одно и то же связанное значение, и многие из них являются промежуточными операциями. Строка означает, что они не являются окончательным результатом. Поэтому, если мы будем хранить все эти строковые объекты в обычной памяти кучи, большая часть кучи будет занята только строковыми объектами, и сборщику мусора придется запускаться чаще, что снизит производительность приложения.

И именно поэтому у нас есть String Constant Pool и процесс интернирования String, всякий раз, когда мы создаем строковый литерал, JVM сначала видит, присутствует ли этот литерал уже в пуле констант или нет, и если он там, новая переменная начнет указывать на тот же объект , этот процесс называется Интернирование строк.

Есть два способа создать объект String

  1. Создание строкового литерала:: все, что подпадает под "", является строковым литералом, например. String s1 = "Naresh", по умолчанию все строковые литералы интернируются и уходят в SCP.
  2. Создание объекта String с помощью конструктора: Если мы создадим объект String с помощью конструктора, например. String s2 = new String("Naresh") объект создается в обычной динамической памяти вместо SCP. И именно поэтому создание объекта String с использованием конструктора не считается лучшей практикой. Мы можем попросить s2 указать на SCP вместо обычной кучи вручную, вызвав для него метод intern(), то есть s2.intern().

Таким образом, чтобы сохранить память, потребляемую строковыми объектами, Java позволяет нескольким ссылочным переменным указывать на один и тот же объект, если они имеют одинаковое значение. Вот почему создатели JVM создали отдельную область памяти SCP для строковых литералов и установили правило, согласно которому, если несколько строковых переменных содержат одно и то же значение, они будут указывать на один и тот же объект.

String a = "Naresh";
String b = "Naresh";
String c = "Naresh";

Для приведенного выше кода будет создан только один объект Naresh, и все ссылочные переменные a, b, c будут указывать на один и тот же объект.

В приведенном выше примере строковый объект со значением Naresh будет создан в SCP только один раз, и все ссылки a, b, c будут указывать на один и тот же объект, но что, если мы попытаемся внести изменения в a, например. a.replace("a", "").

В идеале a должно иметь значение Nresh, но b, c должны оставаться неизменными, поскольку мы, как конечный пользователь, вносим изменения только в a. И мы знаем, что a, b, c все указывают на один и тот же объект, поэтому, если мы внесем изменение в a, другие также должны отразить это изменение.

Но неизменяемость строки спасает нас от этого сценария, и благодаря неизменности строкового объекта строковый объект Naresh никогда не изменится. Поэтому, когда мы вносим какие-либо изменения в a вместо изменения строкового объекта Naresh, JVM создает новый объект, назначая его a, а затем вносит изменения в этот объект.

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

Вы можете найти полный код в этом репозитории Github и, пожалуйста, не стесняйтесь оставлять свои ценные отзывы.

Первоначально опубликовано на www.programmingmitra.com.