#java #string #literals
#java #строка #литералы
Вопрос:
Являются ли приведенные ниже две части кода одинаковыми?
String foo = "foo";
String foo = new String("foo").intern();
Ответ №1:
Они имеют один и тот же конечный результат, но они не совпадают (они будут создавать другой байт-код; new String("foo").intern()
версия фактически проходит через эти шаги, создавая новый объект string, затем интернируя его).
Две соответствующие цитаты из String#intern
:
При вызове
intern
метода, если пул уже содержит строку, равную этомуString
объекту, как определеноequals(Object)
методом, то возвращается строка из пула. В противном случае этотString
объект добавляется в пул и возвращается ссылка на этотString
объект.Все литеральные строки и константные выражения со строковыми значениями интернированы.
Таким образом, конечный результат тот же: переменная, ссылающаяся на интернированную строку «foo».
Комментарии:
1. В этом случае новая строка(«foo»).intern();, вновь созданный объект string не добавляется в кучу, верно?
2. @foo: Вероятно, это так, но оно немедленно доступно для повторного использования GC, поскольку к концу выражения на него нет выдающихся ссылок. И я ожидаю, что оптимизирующая JVM (например, Sun / Oracle HotSpot) в любом случае оптимизирует
new String("foo").intern()
на первом проходе, как только будет отмечено, что при вызове конструктора нет побочных эффектов. Или это может быть не так, потому что, если это не выполняется в тесном цикле, это не соответствует порогу того, чтобы оно того стоило.3. Спасибо за это. Мне было интересно, зачем кому-либо вообще использовать идиому new String («foo») для инициализации строк, когда, если я делаю это таким образом, я создаю два объекта, один в куче, а другой в пуле. Есть ли какое-либо преимущество использования новой строки («foo»), которого мне не хватает, кроме единого шаблона для инициализации всех объектов в Java?
4. @foo: Единственное преимущество, о котором я могу подумать, это то, что если вы не используете
intern
, вы знаете, что ссылка на строку уникальна, даже если содержимое строки таковым не является. Я бы не подумал, что для этого не так много вариантов использования, но посколькуnew String("foo") != "foo"
по определению, это может быть удобно в некоторых случаях. Впрочем, я бы и не подумал, что их немного.
Ответ №2:
Отсюда следует, что для любых двух строк s и t,
s.intern() == t.intern()
является истинным тогда и только тогда, когдаs.equals(t)
являетсяtrue
.
Итак, я полагаю, что ответ «да», хотя второму методу придется выполнять поиск по пулу.
Редактировать
Как предположил Ти Джей Краудер
При вызове метода intern, если пул уже содержит строку, равную этому объекту String, как определено методом equals (Object), то возвращается строка из пула. В противном случае этот строковый объект добавляется в пул и возвращается ссылка на этот строковый объект.
Все литеральные строки и константные выражения со строковыми значениями интернированы.
Комментарии:
1. Я думаю, что более уместными являются две кавычки: «При вызове
intern
метода, если пул уже содержит строку, равную этомуString
объекту, как определеноequals(Object)
методом, тогда возвращается строка из пула. В противном случае этотString
объект добавляется в пул и возвращается ссылка на этотString
объект «. и «Интернируются все литеральные строки и константные выражения со строковым значением».2. Теперь это должно быть на основе JVM, верно? Итак, если у меня есть кластер, то он будет вести себя по-другому.
Ответ №3:
Первый, т.е.
String foo = "foo";
в этой строке мы создаем строку, используя строковые литералы. Это означает, что строка автоматически сохраняется в пуле строковых констант.
Во 2-м, т. е. —
String foo = new String("foo").intern();
Здесь мы создаем строку с помощью new String(), а затем вручную сохраняем ее в пул строковых констант. Если бы у нас не было mentiones intern() , он не был бы сохранен в пуле строковых констант.
Для получения дополнительных разъяснений, пожалуйста, обратитесь к этой ссылке —
http://javacodingtutorial.blogspot.com/2013/12/comparing-string-objects-intern-other.html
Комментарии:
1. Этот ответ не может быть более неправильным. Говорить, что второй фрагмент не будет содержать строку в пуле без вызова
intern()
, очевидно, неправильно, потому что он все еще использует литерал"foo"
. В этом контексте эффектintern
заключается в том, что вызов строкового конструктора больше не имеет значения иfoo
ссылается на литеральную версию"foo"
, а не на вновь созданную.
Ответ №4:
Явное построение нового строкового объекта, инициализированного литералом, создает неинтернированную строку. (Вызов intern() для этой строки вернул бы ссылку на строку из таблицы intern.)
Взято из : http://javatechniques.com/public/java/docs/basics/string-equality.html
Ответ №5:
Да, они одинаковы. В основном intern()
возвращает представление строки, которая уникальна для виртуальной машины. Это означает, что вы можете использовать ==
вместо .equals()
для сравнения строк, экономя на производительности.