Чтобы прояснить исходный вопрос, каждый строковый литерал является константой времени компиляции, но не каждая константа времени компиляции должна происходить из строкового литерала.
Во время выполнения нет никакой разницы между объектом 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
.
Обратите внимание, что этот метод имеет побочный эффект добавления строки в пул, если ее там не было раньше, которая останется там, по крайней мере, до следующего цикла сборки мусора, возможно, до следующего полного сбора мусора, в зависимости от реализации.
Метод test может быть удобен для отладки или удовлетворения любопытства, но нет никакого смысла использовать его в рабочем коде. Код приложения не должен зависеть от этого свойства, и вариант использования, предложенный в комментарии, принудительное использование объединенных строк в критически важном для производительности коде, не является хорошей идеей.
Помимо того, что сам тест является дорогостоящим и противодействует цели повышения производительности, базовое предположение о том, что объединенные в пул строки лучше, чем не объединенные в пул, ошибочно. Отсутствие в пуле не означает, что приложение будет выполнять дорогостоящую реконструкцию каждый раз, когда оно вызывает критически важный для производительности код. Он может просто хранить ссылку в переменной или использовать HashMap
, оба подхода более эффективны, чем вызов intern()
. На самом деле даже временные строки в некоторых случаях могут быть наиболее эффективным решением.
person
Holger
schedule
11.07.2019
readFromFile().intern()
возвращаетfalse
в вашем примере? Это может быть тот же самый объект"foo"
, на который ссылаются где-то еще как на строковый литерал. - person apangin   schedule 10.07.2019ldc
. Таким образом, вполне возможно, что литерал"foo"
вернет тот же объект, который был создан ранееreadFromFile().intern()
. - person apangin   schedule 10.07.20195+6+""
не является строковым литералом, но тем не менее,5+6+"" == "11"
оценивается какtrue
, фактически выражение будет заменено постоянным результатомtrue
даже во время компиляции. Другими словами, «строковые литералы», «константы времени компиляции» и «строки, содержащиеся в пуле времени выполнения» связаны, но все же совершенно разные вещи. Такой метод, какisLiteral("foo")
, сам по себе является противоречием, так как внутри метода ссылка на параметр никогда не является литералом. - person Holger   schedule 10.07.2019String
) и экземпляры строк, содержащиеся (на которые ссылается) пул времени выполнения. - person Holger   schedule 11.07.2019isConst()
, проверяет кадр стека, находит сайт вызова, загружает байт-код и проверяет, была ли инструкция LDC непосредственно перед вызовом. Есть еще несколько сложных случаев: например. должен лиisConst(flag ? "foo" : "bar")
возвращать true. У меня нет опыта работы с агентами JVMTI, но я считаю, что @apangin может это сделать. Хотя я не уверен, подходит ли такое решение для OP. - person Tagir Valeev   schedule 12.07.2019