Итак, вопрос здесь довольно прост: есть ли способ узнать, интерполирован ли String
в Java? Мое предположение - нет, но мне интересно, знает ли кто-нибудь лучше.
Java - скажите, если String интернирован?
Ответ 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);