что делает метод intern в классе string java

Все о String.intern()

Тем, кто знает об этом методе лишь понаслышке, добро пожаловать под кат.

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

Сегодня я просматривал исходный код Xerces (XML-парсер, включенных в Java) и наткнулся на строку, которая меня очень удивила:

com.sun.org.apache.xerces.internal.impl.XMLScanner:395
protected final static String fVersionSymbol = «version».intern();

1) Создать множество (hash set) строк
2) Проверить, что строка (как последовательность символов), с которой вы имеете дело, уже в множестве
3) Если да, то использовать строку из множества
4) В противном случае, добавить эту строку в множество и затем использовать ее

Так почему же я так удивился, увидев
protected final static String fVersionSymbol = «version».intern();
в исходном коде Xerces? Очевидно, что эта строка будет использоваться для многократных сравнений. Имеет ли смысл интернировать ее?

Вывод? intern() является полезным методом и может сделать жизнь легче — но убедитесь, что вы используете его должным образом.

От переводчика
Прошу простить за то, что пару раз исказил исходный текст, чтобы сделать его более понятным (как мне казалось).

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

Update
Думаю, что следующая информация, которую я узнал из других источников будет здесь не лишней:

1. Пул строк хранится в области «Perm Gen», которая зарезервирована для non-user объектов JVM (классы и пр). Если этого не учитывать, вы можете неожиданно получить OutOfMemory Error.
2. Интернированные строки не хранятся вечно. Строки, на которых нет ссылок, также удаляются сборщиком мусора.
3. В большинстве случаев вы не получите существенного прироста производительности от использования intern() — если сравнение строк не является основной (или очень частой) операцией вашего приложения и сравниваемые строки разные по длине.

Источник

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

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

что делает метод intern в классе string java. Смотреть фото что делает метод intern в классе string java. Смотреть картинку что делает метод intern в классе string java. Картинка про что делает метод intern в классе string java. Фото что делает метод intern в классе string java

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

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

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

что делает метод intern в классе string java. Смотреть фото что делает метод intern в классе string java. Смотреть картинку что делает метод intern в классе string java. Картинка про что делает метод intern в классе string java. Фото что делает метод intern в классе string 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.

Источник

Что такое interning и как им пользоваться

Что такое interning? Для чего оно применяется? Когда стоит его применять и какие возможны подводные камни?

что делает метод intern в классе string java. Смотреть фото что делает метод intern в классе string java. Смотреть картинку что делает метод intern в классе string java. Картинка про что делает метод intern в классе string java. Фото что делает метод intern в классе string java

1 ответ 1

Interning — это метод хранения лишь одной копии из многих одинаковых объектов. Применяется в C# и Java к строкам, а также (в Java) к небольшим числам.

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

Это значит, что интернированные объекты можно сравнивать через ReferenceEquals (C#) / == (Java).

Для чего можно пользоваться этим? Например, можно уменьшить расход памяти программы, если в ней используется большое количество строк, среди которых много дубликатов. Например, у вас есть огромный XML-файл, состоящий из почти одинаковых записей. Или огромный текст программы на каком-нибудь языке программирования. Тогда в некоторых случаях можно уменьшить потребление памяти путём интернирования строк: например, все экземпляры while будут одним и тем же объектом.

Внимание! Сама по себе считанная из файла строка не интернируется, даже если она и равна какой-то интернированной строке.

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

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

Далее, интернирование строки делает поиск в глобальных структурах, и поэтому наверняка будет требовать глобальной блокировки. Поэтому несколько потоков, активно применяющих интернирование, будут «сражаться» за общий ресурс.

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

Источник

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

Сравнение строк – увлекательная тема. Мы не только рассмотрим строки в Java, но также проанализируем популярные приемы и решим задачу.

что делает метод intern в классе string java. Смотреть фото что делает метод intern в классе string java. Смотреть картинку что делает метод intern в классе string java. Картинка про что делает метод intern в классе string java. Фото что делает метод intern в классе string java

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

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

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

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

что делает метод intern в классе string java. Смотреть фото что делает метод intern в классе string java. Смотреть картинку что делает метод intern в классе string java. Картинка про что делает метод intern в классе string java. Фото что делает метод intern в классе string javaСтроки в пуле строк

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

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

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

Native-методы

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Ответ

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

Источник

Класс String

Класс String очень часто используется программистами, поэтому его следует изучить очень хорошо.

Следует помнить, что объекты класса String являются неизменяемыми (immutable). Поэтому, когда вам кажется, что вы меняете строку, то на самом деле вы создаёте новую строку.

В Java есть специальные классы StringBuffer и StringBuilder, который допускают изменения в строке.

Классы String, StringBuffer, StringBuilder определены в пакете java.lang и доступны автоматически без объявления импорта. Все три класса реализуют интерфейс CharSequence.

Создать строку очень просто. Например, можно так:

Можно создать массив строк:

Можно создать пустой объект класса String:

Можно создать строку через массив символов:

Есть ещё конструктор, позволяющий задать диапазон символьного массива. Вам нужно указать начало диапазона и количество символов для использования:

Можно создать объект класса String из объекта классов StringBuffer и StringBuilder при помощи следующих конструкторов:

Операторы + и += для String

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

За кулисами Java за нас преобразовало число 4 в строку «4».

Форматирование строк

Предположим у нас есть строковый ресурс:

Чтобы вывести эту строку программно в элементе TextView, можно использовать код:

Представьте себе, что у вас несколько котов. Можно, конечно, завести для каждого кота свою строку. Но ведь строки очень похожи, меняются только имена и возраст. Также можно менять число лап и хвостов (что вы курите?).

Внесём изменения в код:

Если вас есть кот Васька и ему шесть лет, то добавляем две переменные и форматируем строку

Здесь показан простейший пример с форматированием. Помните о нём и применяйте в нужных местах.

Строковой ресурс

Строки желательно хранить в ресурсах (о ресурсах есть отдельная статья).

Программно доступ к строковому ресурсу делается так:

Извлечь строки из строковых массивов в ресурсах

Предположим, у вас есть строковый массив, определённый в файле strings.xml под именем cats_array. Тогда получить доступ к строкам из ресурсов можно так:

Методы

public char charAt (int index)

Возвращает символ с указанным смещением в этой строке. Отсчёт идёт от 0. Не надо использовать отрицательные и несуществующие значения, будьте серьёзнее. Для извлечения нескольких символов используйте getChars().

public int codePointAt(int index)

Возвращает Unicode-символ в заданном индексе

public int codePointBefore(int index)

Возвращает Unicode-символ, который предшествует данному индексу

public int codePointCount(int start, int end)

Вычисляет количество Unicode-символов между позициями start и end

public int compareTo(String string)

Сравнивает указанную строку, используя значения символов Unicode и вычисляет, какая из строк меньше, равна или больше следующей. Может использоваться при сортировке. Регистр учитывается. Если строки совпадают, то возвращается 0, если меньше нуля, то вызывающая строка меньше строки string, если больше нуля, то вызывающая строка больше строки string. Слова с большим регистром стоят выше слова с нижним регистром.

Отсортируем массив строк через пузырьковую сортировку.

В результате мы получим:

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

public int compareToIgnoreCase (String string)

Сравнивает указанную строку, используя значения символов Unicode, без учёта регистра.

public String concat (String string)

Объединяет строку с указанной строкой. Возвращается новая строка, которая содержит объединение двух строк. Обратите внимание, что само имя метода содержит кота!

public boolean contains (CharSequence cs)

Определяет, содержит ли строка последовательность символов в CharSequence

public boolean contentEquals(CharSequence cs)

Сравнивает CharSequence с этой строкой.

public boolean contentEquals(StringBuffer strbuf)

Сравнивает StringBuffer с этой строкой

public static String copyValueOf(char[] data)

Создаёт новую строку, содержащую символы из указанного массива. Изменение массива после создания строки не изменяет созданную строку.

public static String copyValueOf (char[] data, int start, int length)

Создаёт новую строку, содержащую указанные символы из массива data начиная с позиции start (нумерация начинается с нуля) длинной length.

Если указать индекс вне границ строки, то возникнет исключение StringIndexOutOfBoundsException.

public boolean endsWith(String suffix)

Проверяет, заканчивается ли строка символами suffix.

public boolean equals (Object string)

Сравнивает указанный объект и строку и возвращает true, если сравниваемые строки равны, т.е. содержит те же символы и в том же порядке с учётом регистра.

Не путать метод с оператором ==, который сравнивает две ссылки на объекты и определяет, ссылаются ли они на один и тот же экземпляр. Смотри пункт Сравнение строк: equals() или ==?

public boolean equalsIgnoreCase(String string)

Сравнивает указанную строку с исходной строкой без учёта регистра и возвращает true, если они равны. Диапазон A-Z считается равным диапазону a-z.

public static String format(Locale locale, String format, Object. args)

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

Склеиваем два слова, которые выводятся с новой строки. При этом второе слово выводится в верхнем регистре.

Конвертируем число в восьмеричную систему.

По аналогии выводим в шестнадцатеричной системе

Для верхнего регистра используйте %X, тогда вместо ff будет FF.

Для десятичной системы используйте %d.

Дату тоже можно выводить по разному.

Допустим, при выводе double получается 3.0. Как вывести 3, т.е. без нуля. И с учётом того, что например 3.1 должно выводиться как 3.1. Округление здесь не поможет.

public byte[] getBytes()

Конвертируем строку в набор байтов.

public byte[] getBytes(String charsetName)

Возвращает отформатированную строку, используя прилагаемую кодировку.

public void getBytes(int start, int end, byte[] data, int index) и другие перегруженные версии

Метод сохраняет символы в массив байтов, альтернатива методу getChars(). Часто используется при экспорте строк из различных источников, где используются другие символы Unicode. Например, Java по умолчанию использует 16-битовые символы Unicode, а в интернете часто строки используют 8-битовый код Unicode, ASCII и др.

public void getChars(int start, int end, char[] buffer, int index)

Метод для извлечения нескольких символов из строки. Вам надо указать индекс начала подстроки (start), индекс символа, следующего за концом извлекаемой подстроки (end). Массив, который принимает выделенные символы находится в параметре buffer. Индекс в массиве, начиная с которого будет записываться подстрока, передаётся в параметре index. Следите, чтобы массив был достаточного размера, чтобы в нём поместились все символы указанной подстроки.

public int hashCode()

Возвращает целое число — хэш-код для данного объекта.

public int indexOf(int ch)

public int indexOf (int ch, int fromIndex)

Ищет индекс символа сh, начиная с позиции fromIndex

public int indexOf (String str)

public int indexOf (String str, int fromIndex)

Смотри также схожий метод lastIndexOf().

public String intern ()

public boolean isEmpty ()

Проверяет, является ли строка пустой

Данный метод появился в API 9 (Android 2.1). Для старых устройств используйте String.length() == 0

public int lastIndexOf (String string) и другие перегруженные версии

public static String join (CharSequence delimiter, CharSequence. elements)

Метод появился в API 26. Склеивает слова указанным разделителем. Если слово является null, то null будет использоваться в качестве слова. Есть перегруженная версия.

В этом примере мы получаем позицию последней точки и получаем подстроку до неё.

public int length()

Возвращает длину строки

public boolean matches(String regularExpression)

Проверяет, соответствует ли строка регулярным выражениям.

public int offsetByCodePoints (int index, int codePointOffset)

Возвращает позицию, расположенную на расстоянии codePointOffset после начальной позиции, заданной параметром index

public boolean regionMatches (int thisStart, String string, int start, int length)

Метод сравнивает указанную часть строки с другой частью строки. Нужно задать индекс начала диапазон строки вызывающего объекта класса String. Строка для сравнивания передаётся в параметре string. Индекс символа, начиная с которого нужно выполнять сравнение передаётся в параметре start, а длина сравниваемой подстроки в параметре length.

public boolean regionMatches (boolean ignoreCase, int thisStart, String string, int start, int length)

Перегруженная версия. Метод сравнивает указанную часть строки с другой частью строки, игнорируя регистр.

public String replace(CharSequence target, CharSequence replacement) и другие перегруженные версии

Меняет символ или последовательность символов target на replacement

public String replaceAll (String regularExpression, String replacement)

public String replaceFirst (String regularExpression, String replacement)

Удаляет первые символы при помощи регулярного выражения.

Например, если нужно удалить нули в начале чисел 001, 007, 000024, то можно использовать такой вызов.

public String[] split (String regularExpression) и другие перегруженные версии

Разбивает строку на массив из слов. Например, есть строка Васька Рыжик Мурзик Барсик и мы хотим получить массив имён котов:

aCats[0] = Васька
aCats[1] = Рыжик
aCats[2] = Мурзик
aCats[3] = Барсик

Также можно использовать регулярное выражение \\s+, чтобы учитывать любые типы пробелов, включая двойные и более пробелы подряд.

Будьте аккуратны при разбиении по запятой. Часто после запятой идёт пробел, поэтому нужно правильно установить разделитель.

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

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

Также следует быть аккуратным с разделителем |. В регулярных выражениях | является специальным символом. Чтобы использовать вертикальную черту в качестве разделителя, нужно экранировать этот символ с помощью двух обратных слешей «\\|».

public boolean startsWith(String prefix)

Проверяет, начинается ли строка символами prefix с начала строки

public boolean startsWith(String prefix, int start)

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

public CharSequence subSequence (int start, int end)

Аналогичен методу substring(), но может использоваться для CharSequence.

public String substring(int start) и другие перегруженные версии

Если указать индекс вне границ строки, то возникнет исключение StringIndexOutOfBoundsException.

public char[] toCharArray()

Копирует символы в этой строке в массив символов. Тот же результат можно получить через метод getChars(). Документация не рекомендует использовать данный метод, предлагая метод charAt().

public String toLowerCase() и другие перегруженные версии

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

public String toString ()

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

public String toUpperCase()

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

public String trim()

Удаляет пробелы в начале и в конце строки.

public static String valueOf(long value) и другие перегруженные версии

Конвертирует содержимое (числа, объекты, символы, массивы символов) в строку.

Генерируем случайную строку

Допустим, нам нужна случайная строка из заданных символов.

Сравнение строк: equals() или ==?

Хотя в двух переменных содержится одно и то же слово, мы имеем дело с двумя разными объектами и оператор == вернёт false.

Сортировка символов в строке

Есть несколько способов сортировки символов в заданной строке. Рассмотрим их.

Способ первый. Конвертируем строку в массив символов через toCharArray(). Запускаем два цикла. При сравнении символов нужно учитывать их регистр, поэтому мы не только сравниваем разные символы, но и одинаковые, чтобы символы в верхнем и нижнем регистре тоже были отсортированы.

Способ прекрасно работает на английских символах. Но строка «Котёнок» даст неправильный результат: Ккноотё. Символ «ё» попал в самый конец массива.

Способ второй. Обходимся без циклов и используем метод sort().

Переписываем пример с использованием Comparator.

Проблема с «ё» осталась, но с регистрами всё хорошо.

Кстати, в Java 8 можно использовать Stream для подобных операций. В любом случае будьте внимательные с символами другой локали. Ни один пример не решил наших проблем.

StringTokenizer

Класс StringTokenizer разбивает строку на токены с указанным разделителем.

Перевернуть строку

Рассмотрим различные способы решения задачи.

Можно не создавать массив символов, а извлекать каждый символ через метод charAt() и снова использовать цикл, прибавляя к символу предыдущую строку.

Можно воспользоваться готовым методом reverse() класса StringBuffer/StringBuilder.

Экзотический способ при помощи редко используемого класса Stack.

Разбиваем строку на массив символов и кладём каждый символ в стек. Далее начинаем брать элементы с верхушки стека. Из-за особенностей стека (первый вошёл, последний вышел), элементы будут браться задом-наперёд и мы получим нужный результат.

Особо упоротые программисты могут написать примеры с использованием рекурсии и побитового оператора XOR. Эти варианты не будем рассматривать.

Источник

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

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