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

Узнайте о классе String в Java, мотивации сделать его неизменяемым и идее пула констант String. Мы увидим, как манипулируется память, когда мы создаем экземпляры String с помощью литералов String или конструкторов String. Наконец, мы рассмотрим основные преимущества и недостатки, вызванные неизменяемостью класса String.

1. Неизменяемые строки в Java

Строка — это последовательность символов. В Java, как и в других языках программирования, строки являются частью предопределенных типов. В Java есть класс java.lang.String, экземпляры которого представляют строки.

Класс String является неизменяемым классом. Неизменяемость означает, что строка не может быть изменена после создания ее экземпляра.

Обычно многие конфиденциальные данные(имена пользователей, пароли, URL-адреса, порты, базы данных, сокетные соединения) представляются и передаются в виде строк. Благодаря тому, что эта информация неизменяема, код становится защищенным от широкого спектра угроз безопасности.

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

В изменяемом контексте изменение строкового литерала может привести к повреждению переменных.

2. Что такое пул строковых констант в Java?

Память в Java делится на три части: куча, стек и строковый пул. Строковый константный пул — это специальная область, используемая для хранения строковых литералов.

  • Обратите внимание, что до Java 7 пул строк был частью области памяти постоянной генерации.
  • Начиная с Java 7, строки размещаются в области кучи Java вместе с другими объектами, созданными приложением.
  • Позднее, в Java 8, постоянная генерация была полностью удалена.

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

Хотя пул строк был перемещен из пространства Permgen в область памяти кучи, все концепции, связанные с созданием строк, литералами, объектами и интернированием, не изменились.

Строковая константа Java Pool0

3. Разница между строковыми литералами и строковыми объектами

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

String strLiteral = "Hello World";String strObj = new String("Hello World");

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

Давайте рассмотрим пример.

String a = "howtodoinjava";String b = "howtodoinjava";System.out.println(a == b); //true

В приведенной выше программе мы создали два строковых литерала с одинаковым содержимым. После создания 'a' в пуле строк следующий строковый литерал 'b' указывает на тот же объект в области памяти, поэтому 'a == b' является истинным.

String a = "howtodoinjava";String b = "howtodoinjava";System.out.println(a == b);String c = new String("howtodoinjava");System.out.println(a == b); //trueSystem.out.println(b == c); //false

В приведенной выше программе мы создали новый объект String с похожим содержимым. Когда мы проверяем равенство ссылок на объекты, мы видим, что b и c указывают на разные объекты. Это означает, что когда мы создали объект String c, в памяти был создан новый объект.

Строковая константа Java Pool1

4. API String.intern()

Мы знаем, что строковые литералы создаются в пуле строк, а строковые объекты создаются в области памяти кучи.

Мы можем использовать метод String.intern() для создания строковых литералов для строковых объектов. При вызове на строковом объекте метод intern() создает точную копию объекта String в куче памяти и сохраняет ее в пуле констант String.

String a = "howtodoinjava";String b = "howtodoinjava";String c = new String("howtodoinjava");String d = c.intern();

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

5. Преимущества

5.1. Усиленная безопасность

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

Поскольку мы не можем изменять неизменяемые объекты, это помогает сделать безопасность еще более эффективной.

5.2 Безопасность потока

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

Любой неизменяемый объект является потокобезопасным по своей природе. Это означает, что несколько потоков могут совместно использовать и манипулировать строками без риска повреждения и несогласованности.

6. Недостатки

6.1 Класс String не может быть расширен

Если мы хотим расширить класс String, чтобы добавить больше функций, мы не можем этого сделать. Неизменяемый класс объявляется final, чтобы избежать расширяемости.

Но, к счастью, у нас есть много сторонних библиотек(Apache Commons Lang, Spring Framework, Guava), которые предоставляют отличные служебные классы практически для всех видов использования.

6.2 Конфиденциальные данные в памяти на долгое время

Конфиденциальные данные в строках(например, пароли) могут находиться в памяти(в SCP) в течение более длительного времени, поскольку SCP использует преимущества специальной обработки от сборщика мусора. Сборщик мусора не посещает SCP с той же частотой(циклами), что и другие зоны памяти.

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

Чтобы избежать этого потенциального недостатка, рекомендуется хранить конфиденциальные данные(например, пароли) в char[] вместо String.

6.3 Возможная ошибка OutOfMemoryError

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

Прокрутить вверх