Определите, является ли String константой времени компиляции - PullRequest
0 голосов
/ 10 июля 2019

Имея ссылку на любой String, можно ли программно определить, является ли это ссылкой на постоянную времени компиляции?
Или, если это не так, хранится ли она во внутреннем пуле без выполнения s.intern() == s?

isConst("foo")                       -> true
isConst("foo" + "bar")               -> true   // 2 literals, 1 compile time string
isConst(SomeClass.SOME_CONST_STRING) -> true
isConst(readFromFile())              -> false
isConst(readFromFile().intern())     -> false  // true would be acceptable too

(контекст для комментариев ниже: вопрос, изначально задаваемый о литералах)

1 Ответ

2 голосов
/ 11 июля 2019

Чтобы прояснить исходный вопрос, каждый строковый литерал является константой времени компиляции, но не каждая константа времени компиляции должна происходить из строкового литерала.

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

Из этого ответа можно извлечь метод, позволяющий просто определить, находится ли строка в пуле или нет:

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

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

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

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

Помимо того факта, что сам тест стоит дорого и противодействует цели повышения производительности, основополагающее предположение о том, что объединенные строки лучше, чем не объединенные, ошибочно. Отсутствие в пуле не означает, что приложение будет выполнять дорогостоящее восстановление каждый раз, когда оно вызывает критичный для производительности код. Он может просто содержать ссылку в переменной или использовать HashMap, оба подхода более эффективны, чем вызов intern(). Фактически, даже временные строки могут быть наиболее эффективным решением в некоторых случаях.

...