Java строковый стажер и литерал

#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:

public String intern()

Отсюда следует, что для любых двух строк 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() для сравнения строк, экономя на производительности.