Что такое пул строк java

Java Challengers #2: Сравнение строк

У нас как всегда много опаздывающих к началу курса, так что только вчера провели второе занятие среди нового потока «Разработчик Java». Но это так, мелочи жизни, а пока что мы продолжаем публикацию серии статей Java Challengers, перевод которых подготовили для вас.

Что такое пул строк java. Смотреть фото Что такое пул строк java. Смотреть картинку Что такое пул строк java. Картинка про Что такое пул строк java. Фото Что такое пул строк java

Когда вы смотрите на класс String в Java, вы можете увидеть как инкапсулирован массив char :

Чтобы лучше понять инкапсуляцию, представьте физический объект: машину. Нужно ли вам знать, как работает автомобиль под капотом, чтобы управлять им? Конечно, нет, но вы должны знать, что делают интерфейсы автомобиля: педаль газа, тормоза и рулевое колесо. Каждый из этих интерфейсов поддерживает определенные действия: ускорение, торможение, поворот налево, поворот направо. То же самое и в объектно — ориентированном программировании.

Что такое пул строк (String pool)

Что такое пул строк java. Смотреть фото Что такое пул строк java. Смотреть картинку Что такое пул строк java. Картинка про Что такое пул строк java. Фото Что такое пул строк java

Строки в пуле строк

Исключение — оператор new

Теперь посмотрите на этот код — он выглядит похожим на предыдущий пример, но здесь есть отличие.

Native-методы в Java — это методы, которые будут компилироваться с использованием языка C, обычно с целью управления памятью и оптимизации производительности.

Пулы строк и метод intern()

Для хранения строк в пуле используется способ, называемый «интернирование строк» (String interning).

Вот, что Javadoc говорит нам о методе intern() :

Метод intern() используется для хранения строк в пуле строк. Во-первых, он проверяет, существует ли уже созданная строка в пуле. Если нет, то создает новую строку в пуле. Логика пула строк основана на паттерне Flyweight.

Теперь, обратите внимание, что происходит, когда мы используем new для создания двух строк:

Метод equals в классе String

Наиболее распространенные методы String

Есть ещё одна вещь, которую вам нужно знать, прежде чем решить задачку на сравнение строк.

Рассмотрим наиболее распространённые методы класса String :

Решите задачку на сравнение строк

Правильный ответ приведён в конце статьи.

Что сейчас произошло? Понимание поведения String

В первой строке мы видим:

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

Окончательно, мы имеем:

Распространенные ошибки со строками

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

Использование методов класса String для сравнения ссылок на объекты также может быть сложным. Особенность в том, что если метод изменяет что-то в строке, то будут разные ссылки на объекты.

Несколько примеров, которые помогут прояснить:

Это сравнение будет истинным, потому что метод trim() не создает новую строку.

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

Наконец, когда trim() выполнит свою работу, он создает новую строку:

Что нужно помнить о строках

Строки не изменяемые, поэтому состояние строки изменить нельзя.

Для экономии памяти JVM хранит строки в пуле строк. При создании новой строки JVM проверяет ее значение и указывает на существующий объект. Если в пуле нет строки с этим значением, то JVM создаёт новую строку.

Оператор » == » сравнивает ссылки на объект. Метод equals() сравнивает значения строк. То же правило будет применяться ко всем объектам.

При использовании оператора new будет создана новая строка в хипе (Прим. переводчика — в оригинале написано, что в пуле, но это не так, спасибо zagayevskiy), даже если есть строка с тем же значением.

Ответ

Ответ на эту задачу — D. Вывод будет 12568.

Источник

Руководство по пулу строк Java

Узнайте, как JVM оптимизирует объем памяти, выделенный для хранения строк в пуле строк Java.

1. Обзор

Объект String является наиболее часто используемым классом в языке Java.

2. Интернирование строк

Благодаря неизменяемости Строк в Java JVM может оптимизировать объем выделенной для них памяти, храня только одну копию каждого литерала Строки в пуле . Этот процесс называется интернированием .

Когда мы создаем переменную String и присваиваем ей значение, JVM ищет в пуле String равного значения.

Если он будет найден, компилятор Java просто вернет ссылку на свой адрес памяти, не выделяя дополнительной памяти.

Если он не найден, он будет добавлен в пул (интернет), и его ссылка будет возвращена.

Давайте напишем небольшой тест, чтобы проверить это:

3. Строки, выделенные с помощью конструктора

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

Давайте посмотрим, чем это отличается от предыдущего случая:

4. Строковый литерал против строкового объекта

Когда мы создаем объект String с помощью оператора new () , он всегда создает новый объект в памяти кучи. С другой стороны, если мы создадим объект с использованием синтаксиса String literal, например “Baeldung”, он может вернуть существующий объект из пула строк, если он уже существует. В противном случае он создаст новый строковый объект и поместит его в пул строк для последующего повторного использования.

В этом примере объекты String будут иметь одну и ту же ссылку.

Затем давайте создадим два разных объекта с помощью new и проверим, что у них разные ссылки:

5. Ручная Стажировка

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

Ручное интернирование строки | сохранит ее ссылку в пуле, и JVM вернет эту ссылку при необходимости.

Давайте создадим тестовый случай для этого:

6. Сбор Мусора

7. Производительность и оптимизация

В Java 6 единственная оптимизация, которую мы можем выполнить, – это увеличение пространства PermGen во время вызова программы с помощью параметра MaxPermSize JVM:

В Java 7 у нас есть более подробные параметры для изучения и расширения/уменьшения размера пула. Давайте рассмотрим два варианта просмотра размера пула:

Если мы хотим увеличить размер пула с точки зрения ведер, мы можем использовать параметр StringTableSize JVM:

До Java 7u40 размер пула по умолчанию составлял 1009 ведер, но это значение было подвержено нескольким изменениям в более поздних версиях Java. Если быть точным, размер пула по умолчанию с Java 7u40 до Java 11 составлял 60013, а теперь он увеличился до 65536.

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

8. Примечание О Java 9

В Java 9 предоставляется новое представление, называемое Compact Strings. Этот новый формат будет выбирать соответствующую кодировку между char[] и byte[] в зависимости от сохраненного содержимого.

Поскольку новое представление String будет использовать кодировку UTF-16 только в случае необходимости, объем кучи памяти будет значительно ниже, что, в свою очередь, приведет к меньшим затратам Сборщика мусора на JVM.

9. Заключение

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

Источник

Собеседование по Java — работа со строками (String in Java) (вопросы и ответы)

Список вопросов и ответов для собседования по Java по теме «Работа со строками».

К списку вопросов по всем темам

Вопросы

1. Какие “строковые” классы вы знаете?
2. Какие основные свойства “строковых” классов (их особенности)?
3. Можно ли наследовать строковый тип, почему?
4. Дайте определение понятию конкатенация строк.
5. Как преобразовать строку в число?
6. Как сравнить значение двух строк?
7. Как перевернуть строку?
8. Как работает сравнение двух строк?
9. Как обрезать пробелы в конце строки?
10. Как заменить символ в строке?
11. Как получить часть строки?
12. Дайте определение понятию “пул строк”.
13. Какой метод позволяет выделить подстроку в строке?
14. Как разбить строку на подстроки по заданному разделителю?
15. Какой метод вызывается для преобразования переменной в строку?
16. Как узнать значение конкретного символа строки, зная его порядковый номер в строке?
17. Как найти необходимый символ в строке?
18. Можно ли синхронизировать доступ к строке?
19. Что делает метод intern()?
20. Чем отличаются и что общего у классов String, StringBuffer и StringBuilder?
21. Как правильно сравнить значения строк двух различных объектов типа String и StringBuffer?
22. Почему строка неизменная и финализированная в Java?
23. Почему массив символов предпочтительнее строки для хранения пароля?
24. Почему строка является популярным ключом в HashMap в Java?
25. Напишите метод удаления данного символа из строки.

Ответы

1. Какие “строковые” классы вы знаете?

2. Какие основные свойства “строковых” классов (их особенности)?

Все строковые классы — final (следовательно от них нельзя унаследоваться).

String.
Строка — объект, что представляет последовательность символов. Для создания и манипулирования строками Java платформа предоставляет общедоступный финальный (не может иметь подклассов) класс java.lang.String. Данный класс является неизменяемым (immutable) — созданный объект класса String не может быть изменен.

StringBuffer
Строки являются неизменными, поэтому частая их модификация приводит к созданию новых объектов, что в свою очередь расходует драгоценную память. Для решения этой проблемы был создан класс java.lang.StringBuffer, который позволяет более эффективно работать над модификацией строки. Класс является mutable, то есть изменяемым — используйте его, если Вы хотите изменять содержимое строки. StringBuffer может быть использован в многопоточных средах, так как все необходимые методы являются синхронизированными.

StringBuilder
StringBuilder — класс, что представляет изменяемую последовательность символов. Класс был введен в Java 5 и имеет полностью идентичный API с StringBuffer. Единственное отличие — StringBuilder не синхронизирован. Это означает, что его использование в многопоточных средах нежелательно. Следовательно, если вы работаете с многопоточностью, Вам идеально подходитStringBuffer, иначе используйте StringBuilder, который работает намного быстрее в большинстве реализаций.

Обработка строк в Java. Часть I: String, StringBuffer, StringBuilder: http://habrahabr.ru/post/260767/

3. Можно ли наследовать строковый тип, почему?

Классы объявлены final, поэтому наследоваться не получится.

4. Дайте определение понятию конкатенация строк.

Конкатенация — операция объединения строк, что возвращает новую строку, что является результатом объединения второй строки с окончанием первой. Операции конкатенации могут быть выполнены так:

Сравнение производительности конкатенации строк:
Оператор ‘+=’ > 92.243 с;
String.concat() > 1.254 с;
StringBuffer > 1.208 с;
StringBuilder > 1.121 с.

Конкатенация и настройки JVM: http://microfork.com/string-concatenation-java/

5. Как преобразовать строку в число?

6. Как сравнить значение двух строк?

7. Как перевернуть строку?

8. Как работает сравнение двух строк?

Метод equals сравнивает посимвольно на эквивалентность.

9. Как обрезать пробелы в конце строки?

10. Как заменить символ в строке?

11. Как получить часть строки?

Метод substring(int beginIndex, int lastIndex) — возвращает часть строки по указанным индексам.

12. Дайте определение понятию “пул строк”.

Пул строк – это набор строк, который хранится в памяти Java heap. Мы знаем, что String это специальный класс в Java, и мы можем создавать объекты этого класса, используя оператор new точно так же, как и создавать объекты, предоставляя значение строки в двойных кавычках.
Диаграмма ниже объясняет, как пул строк размещается в памяти Java heap и что происходит, когда мы используем различные способы создания строк.

Что такое пул строк java. Смотреть фото Что такое пул строк java. Смотреть картинку Что такое пул строк java. Картинка про Что такое пул строк java. Фото Что такое пул строк java

Пул строк возможен исключительно благодаря неизменяемости строк в Java и реализации идеи интернирования строк. Пул строк также является примером паттерна Приспособленец (Flyweight).
Пул строк помогает экономить большой объем памяти, но с другой стороны создание строки занимает больше времени.
Когда мы используем двойные кавычки для создания строки, сначала ищется строка в пуле с таким же значением, если находится, то просто возвращается ссылка, иначе создается новая строка в пуле, а затем возвращается ссылка.
Тем не менее, когда мы используем оператор new, мы принуждаем класс String создать новый объект строки, а затем мы можем использовать метод intern() для того, чтобы поместить строку в пул, или получить из пула ссылку на другой объект String с таким же значением.

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

13. Какой метод позволяет выделить подстроку в строке?

14. Как разбить строку на подстроки по заданному разделителю?

Мы можем использовать метод split(String regex) для разделения строки на массив символов, используя в качестве разделителя регулярное выражение. Метод split(String regex, int numOfStrings) является перегруженным методом для разделения строки на заданное количество строк. Мы можем использовать обратную черту для использования специальных символов регулярных выражений в качестве обычных символов.

15. Какой метод вызывается для преобразования переменной в строку?

16. Как узнать значение конкретного символа строки, зная его порядковый номер в строке?

str.charAt(int i) вернет символ по индексу.

17. Как найти необходимый символ в строке?

str.indexOf(char ch) или lastIndexOf(char c) — вернет индекс первого и последнего вхождения символа.

18. Можно ли синхронизировать доступ к строке?

19. Что делает метод intern()?

20. Чем отличаются и что общего у классов String, StringBuffer и StringBuilder?

В дополнение к ответу вначале приведу сравнение производительности классов.

Сравнение производительности. Linux

КлассOpen JDK 1.6.0_18HotSpot 1.6.0_20JRockit 4.0.1
String27390ms26850ms26940ms
StringBuffer35.55ms34.87ms15.41ms
StringBuilder33.01ms31.78ms12.82ms

Сравнение производительности. Windows XP:

КлассHotSpot 1.6.0_20JRockit 4.0.1
String55260ms45330ms
StringBuffer19.38ms14.50ms
StringBuilder16.83ms12.76ms

21. Как правильно сравнить значения строк двух различных объектов типа String и StringBuffer?

Привести их к одному типу и сравнить.

22. Почему строка неизменная и финализированная в Java?

Есть несколько преимуществ в неизменности строк:

23. Почему массив символов предпочтительнее строки для хранения пароля?

Строка неизменяемая в Java и хранится в пуле строк. С тех пор, как она была создана, она остается в пуле, пока не будет удалена сборщиком мусора, поэтому, когда мы думаем, что закончили работу с паролем, он остается доступным в памяти некоторое время, и нет способа избежать этого. Это риск безопасности, поскольку кто-либо, имеющий доступ к дампу памяти сможет найти пароль в виде чистого текста.
Если мы используем массив символов для хранения пароля, мы можем очистить его после того, как закончим с ним работать. Таким образом, мы можем контролировать, как долго он находится в памяти, что позволяет избежать риска безопасности, свойственного строке.

24. Почему строка является популярным ключом в HashMap в Java?

Поскольку строки неизменны, их хэшкод кэшируется в момент создания, и не требует повторного пересчета. Это делает строки отличным кандидатом для ключа в Map и они обрабатываются быстрее, чем другие объекты-ключи HashMap. Вот почему строки преимущественно используются в качестве ключей HashMap.

25. Напишите метод удаления данного символа из строки.

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

Источник

“String pool в Java” или почему не надо сравнивать строки при помощи “==”

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

Метод, в котором возникала ошибка, очевидно нуждался в рефакторинге. Он использовал не самые прозрачные конструкции и был плохо читаем. Метод принимал два параметра типа String : первый – ключ, второй – значение. В блоках if осуществлялась проверка ключа на равенство некоторому строковому литералу, в случае совпадения компилировался экземпляр java.util.regex.Pattern соответствующего регулярного выражения, затем при помощи java.util.regex.Matcher.find() проверялось наличие подстроки в полученном значении. Ниже похожий метод, который я набросал “по памяти”:

Обратите внимание, как осуществляется проверка строк на эквивалентность – сравниваются не значения, а ссылки на объекты в куче. В Java литературе такой подход считается bad practice, ведь совершенно необязательно, что две одинаковые (по содержанию) строки являются одним и тем же объектом. Но если вы запустите этот код в своей IDE, он может оказаться вполне работоспособным и вернёт ожидаемый результат.

Пул строк в Java

Что такое пул строк java. Смотреть фото Что такое пул строк java. Смотреть картинку Что такое пул строк java. Картинка про Что такое пул строк java. Фото Что такое пул строк java

Что такое пул строк java. Смотреть фото Что такое пул строк java. Смотреть картинку Что такое пул строк java. Картинка про Что такое пул строк java. Фото Что такое пул строк java

Ссылки a и b по-прежнему указывают на один и тот же объект, в то время как ссылка c указывает на новый объект, о чём свидетельствует false в выводе консоли. То есть использование оператора new при создании новой строки приводит к созданию нового объекта ( не может быть! ), даже если аналогичная по значению строка уже создавалась ранее и сохранена в пуле строк.

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

Напишем метод, который будет генерировать случайную строку некоторой длины:

Модифицируем метод main:

Что такое пул строк java. Смотреть фото Что такое пул строк java. Смотреть картинку Что такое пул строк java. Картинка про Что такое пул строк java. Фото Что такое пул строк java

Снова вызовем метод main и посмотрим в консоль:

Что такое пул строк java. Смотреть фото Что такое пул строк java. Смотреть картинку Что такое пул строк java. Картинка про Что такое пул строк java. Фото Что такое пул строк java

На этот раз псевдослучайные строки в обоих случаях посимвольно равны, но ссылаются на разные объекты кучи. Почему? Думаю, что в этом случае добавление строки в пул не произошло. Давайте исправим это, вызвав метод intern перед возвратом из метода getRandomStr :

Что такое пул строк java. Смотреть фото Что такое пул строк java. Смотреть картинку Что такое пул строк java. Картинка про Что такое пул строк java. Фото Что такое пул строк java

Что такое пул строк java. Смотреть фото Что такое пул строк java. Смотреть картинку Что такое пул строк java. Картинка про Что такое пул строк java. Фото Что такое пул строк java

Но native не значит “быстрый”. Стоимость вызова intern может варьироваться в зависимости от используемой JVM, поэтому относится к его использованию нужно с осторожностью.

Интернирование строк

Давайте рассмотрим метод intern подробнее. Его описание из javadoc для Java 8:

Выводы

А еще метод equals может быть интринсифицирован, то есть заменён на intrinsic-функцию JIT-компилятором. Подробнее об интринсиках можно почитать в статье на хабре.

Обновление:

Интереснейшая статья Алексей Шипилёва, демонстрирующая аспекты производительности интернирования строк в OpenJDK (подсказка: все несколько сложнее, чем кажется на первый взгляд).

Источник

Что такое пул строк в Java?

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

ОТВЕТЫ

Ответ 1

Это выводит true (хотя мы не используем метод equals : правильный способ сравнения строк)

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

Имя «пул строк» ​​исходит из идеи, что вся уже определенная строка хранится в некотором «пуле» и перед созданием нового компилятора объекта String проверяет, определена ли такая строка.

Ответ 2

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

В случае 1 буквально s1 создается и сохраняется в пуле. Но в случае 2, буква s2 ссылается на s1, вместо этого он не будет создавать новый.

Ответ 3

Начните с цитаты из спецификации виртуальной машины:

Загрузка класса или интерфейса, который содержит строковый литерал, может создать новый объект String (§2.4.8) для представления этого литерала. Это может не произойти, если объект String уже создан для представления предыдущего вхождения этого литерала или если метод String.intern был вызван на объект String, представляющий ту же строку, что и литерал.

Это не тот случай, если мы используем конструктор:

Опять же, «one» создается в пуле, но затем мы создаем новый экземпляр из одного и того же литерала, и в этом случае он приводит к (a == b) && (a.equals(b)) == false

Итак, почему у нас есть пул строк? Строки и особенно строковые литералы широко используются в типичном Java-коде. И они неизменны. И, будучи непреложным, можно кэшировать String для экономии памяти и повышения производительности (меньше усилий для создания, меньше мусора для сбора).

В качестве программистов нам не нужно много заботиться о пуле String, если мы помним:

Ответ 4

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *