Подтвердить что ты не робот

Java - скажите, если String интернирован?

Итак, вопрос здесь довольно прост: есть ли способ узнать, интерполирован ли String в Java? Мое предположение - нет, но мне интересно, знает ли кто-нибудь лучше.

4b9b3361

Ответ 1

Единственный способ узнать, является ли интервал String состоящим в вызове intern() и проверить, возвращается ли он:

boolean hasBeenInternedBefore = myString.intern() == myString;

Это, очевидно, имеет недостаток интернирования String, когда он раньше не был интернирован.

Переход частично не по теме, есть способ сделать "обычай" интернирования с явным пулом, используя Interner interface Guava (используя реализации, представленные Interners class). Это имеет то преимущество, что позволяет самому Interner (и пускать пул) собирать мусор, когда он больше не ссылается.

Ответ 2

Существует способ проверить, был ли уже определенный объект String уже интернирован, но он вставляет содержимое в пул строк, если это содержимое не было интернировано. Создайте новый объект String с тем же содержимым, ставьте его и сравните с исходным объектом:

new String(s).intern() == s

Это работает из-за того, что new String(s) != s. Рассмотрим каждую возможную ситуацию:

  • s интернирован в пуле строк. new String(s) имеет то же содержимое, что и s, поэтому вызываемый intern() возвращает s. Результат выражения true.
  • s не интернирован в пуле строк, но другой равный String объект - пусть называет его s2. intern() вернет s2, поэтому результат выражения false.
  • s не интернирован в пуле строк, и ни один String не равен ему. В этом случае new String(s) будет интернирован в пул строк, что, к сожалению, модифицирует пул строк. Поскольку это не тот же объект String, что и s, результатом выражения является false.

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

public static void main(String[] args) {
    String interned = new String(new char[] { 'i', 'n', 't' }).intern();
    String notInterned = new String(new char[] { 'n', 'o', 't' });
    System.out.println("Case 1: " + wasInterned(interned));
    System.out.println("Case 2: " + wasInterned(new String(interned)));
    System.out.println("Case 3: " + wasInterned(notInterned));
}

public static boolean wasInterned(String s) {
    return new String(s).intern() == s;
}

При запуске вывод:

 Case 1: true
 Case 2: false
 Case 3: false

Ответ 3

Мы не можем заглянуть внутрь репозитория интернированных строк и не можем получить набор всех интернированных строк.

Тестирование, если заданная строка была интернирована, уже создает приятную дилемму (общая проблема с измерениями кстати): само измерение может повлиять на хранилище интернированных строк;)

Чтобы проверить, содержит ли репозиторий данный String, нам нужно сравнить String с (наихудшим случаем) все строки в этом репозитории - с риском, что JVM ставит эту ссылочную строку перед тем, как мы начнем сравнивать... что return a true, хотя String не была интернирована перед тестом;)

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

Ответ 4

Нет. Вообще говоря, вам не нужно проверять - просто intern их, чтобы быть уверенными или не полагаться на интернирование. Если вам нужны интернированные или не интернированные строки для тестирования или экспериментов, вы можете сделать их:

интернирован:

s = someArbitraryString.intern();

Non-интернирован:

s = new String(someArbitraryString);