Когда использовать intern () для строковых литералов - PullRequest
37 голосов
/ 02 декабря 2009

Я вижу много унаследованного кода, подобного этому:

class A {
    public static final String CONSTANT = "value".intern();
    ...
}

Я не вижу никакой причины для intern (), поскольку в Javadoc можно прочитать: «Все литеральные строки и строковые константные выражения интернированы». Есть ли какое-то намерение в этом, может быть, в прошлых версиях языка?

Ответы [ 4 ]

68 голосов
/ 02 декабря 2009

Этот метод гарантирует, что CONSTANT на самом деле не является константой.

Когда компилятор Java видит ссылку на конечный статический примитив или String, он вставляет фактическое значение этой константы в класс, который ее использует. Если затем вы измените значение константы в определяющем классе, но не перекомпилируете класс using, он продолжит использовать старое значение.

Вызывая intern () для строки «constant», он больше не считается статической константой компилятором, поэтому класс using будет фактически обращаться к члену определяющего класса при каждом использовании.


JLS цитаты:

17 голосов
/ 02 декабря 2009

Использование intern() с константным строковым литералом является пустой тратой времени, так как литерал уже будет интернирован, как указано в разделе 3.10.5. Строковые литералы из Спецификация языка Java® .

Цитирование из Java SE 8 Edition:

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

Полагаю, кодер не оценил этот факт.

Edit:

Как указывало kdgregory , существует влияние на то, как эта константа может быть встроена.

1 - https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5

7 голосов
/ 02 декабря 2009

Некоторое время назад я интернировал () редактирование всех строк, поступающих из файлов классов (для анализатора файлов классов). Intern () заставил программу использовать меньше памяти (в данном случае не будет, как указывали другие), но значительно замедлил работу программы (я думаю, что для анализа всего файла rt.jar потребовалось 4 секунды, и это изменение положило его более 8 секунд). Рассматривая его в то время (был JDK 1.4, я думаю), код intern () довольно уродлив и медленнее, чем, вероятно, должен быть.

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

0 голосов
/ 10 января 2012

Я использовал intern () для «блокировки». Например, допустим, у меня есть «хранилище» «торговых записей». Пока я редактирую и обновляю сделку, я хочу заблокировать сделку; Вместо этого я мог бы заблокировать tradeId.intern (), чтобы мне не пришлось беспокоиться о клонах сделки, плавающей вокруг. Я не уверен, всем ли нравится это использование.

Предполагается, что поле id вряд ли случайно столкнется с полем id другого объекта домена - например, tradeId не конфликтует с account_number, где можно также делать

synchronized(account.getAccountNumber().intern()) {...}

см. пример

...