Строковое литералы и отношение объектов в Java [дубликат]

Посмотрите на этот пример Plnkr

Переменная this сильно отличается timesCalled с каждым нажатием кнопки увеличивается только на 1. Ответ на мой личный вопрос:

.click( () => { } )

и

.click(function() { })

создают одинаковое количество функции при использовании в цикле, как вы можете видеть из подсчета Guid в Plnkr.

17
задан Brian Rasmussen 4 April 2013 в 16:48
поделиться

7 ответов

Процесс объединения одинаковых строк называется « interning » и уже много лет выполняется множеством компиляторов языка, но не всегда. Ответ на этот вопрос, особенно в том виде, в котором он расширился: Геннадий Ванин - Новосибирск, зависит от языка и реализации компилятора. Для Java все константные строки интернированы, как того требует спецификация языка Java . Но это только постоянные строковые выражения, и только тогда, когда они скомпилированы в одно и то же время. Если у вас есть две строки Java, достаточно разделенные во времени и пространстве (, например, , скомпилированные в отдельные файлы JAR), они не будут тем же самым объектом. Аналогично, динамически созданные строки Java (, например , вывод различных методов toString()) не будут интернированы, если метод специально не запрашивает его через String.intern(). И да, все используемые интернированные строки будут разделять одни и те же ячейки памяти - это большая часть того, почему строки интернированы в первую очередь.

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

18
ответ дан Ross Patterson 19 August 2018 в 08:12
поделиться
  • 1
    @ Росс Паттерсон Спасибо вам большое! Это хорошо объясняет концепцию и является идеальным ответом на мои сомнения – Reshma Ratheesh 5 April 2013 в 08:07
  • 2
    @Ross Patterson, Спасибо за внимание. Но я предполагаю, что это не по времени и пространству, а по одно и то же выполнение JVM (поскольку JVM может быть восстановлен). – Gennady Vanin Геннадий Ванин 5 April 2013 в 11:26
  • 3
    Ответ неправильный. Все строки, которые были объединены во время компиляции, также проверяются во время выполнения загрузчиком классов независимо от того, из какого класса или JAR они происходят. – user207421 18 January 2017 в 13:30
  • 4
    «Если у вас есть две строки Java, достаточно разделенные во времени и пространстве (например, скомпилированные в отдельные файлы JAR), они не будут одним и тем же объектом. & quot; Как правильно указано @EJP, это неправильная и полная глупость (что, черт возьми, время и пространство даже означают в этом контексте?). Пожалуйста, исправьте это. Ответ ниже Геннадия описывает все правильные правила. – Oleg 16 September 2017 в 23:43

Когда компилятор оптимизирует ваши строковые литералы, он видит, что оба s1 и s2 имеют одинаковое значение и, следовательно, вам нужен только один строковый объект. Это безопасно, потому что String неизменна в Java.

String s1="Java";
String s2="Java";
System.out.println(s1== s2);

Это дает результат true, потому что s1 и s2 указывают на один и тот же объект.

String Pool - это механизм, который все уже определенная строка хранится в некотором «пуле», и перед созданием нового компилятора объекта String проверяет, определена ли такая строка.

5
ответ дан Achintya Jha 19 August 2018 в 08:12
поделиться
  • 1
    Неправильно. Вы можете создавать экземпляры String с помощью StringBuilder, и если вы создадите строку, которая уже используется в другом месте в качестве литерала, это не будет !!! быть одной и той же строкой, а также той же ячейкой памяти. Вот почему все сравнения строк должны выполняться с использованием .equals. Строка является ссылочным типом. – TheBlastOne 4 April 2013 в 09:03
  • 2
    Только если у вас есть задания, как показано в строке строки, литералы выделяются только один раз. – TheBlastOne 4 April 2013 в 09:04
  • 3
    @TheBlastOne Я упомянул что-то неправильно выше? – Achintya Jha 4 April 2013 в 09:09
  • 4
    @TheBlastOne Вы можете вручную установить строку: String#intern() . – maba 4 April 2013 в 09:28
  • 5
    @AchintyaJha yes & quot; Это безопасно, потому что String неизменна в Java. & Quot; в то время как строки являются неизменными в Java, это не означает, что безопасно сравнивать их с помощью «== & quot; в любом случае. – TheBlastOne 4 April 2013 в 12:19

Пример.

Первый пример

String s1 = "FirstString";
String s2 = "FirstString";

 if(s1 == s2) {
   //This condition matched true because java don't make separate object for these two string. Both strings point to same reference.
 }

Второй пример

String s1= "FirstString";
String s2 = new String("FirstString");

if(s1.equals(s2)) {
  //This condition true because same content.
}

if(s1 == s2) {
  //This condition will be false because in this java allocate separate reference for both of them
}

Заключение: Java проверяет, существует ли строка или нет. Если мы создадим объект второй строки с использованием нового и имеем разный контент, тогда он создает объект и назначает другую ссылку, а в случае Если мы не создаем объект с использованием нового и не будем иметь один и тот же контент, тогда его назначение будет иметь ту же ссылку, что и первая строка, .

2
ответ дан Ajay S 19 August 2018 в 08:12
поделиться
  • 1
    Ваше заключение неверно. Если вы используете new, вы всегда получаете новый объект строки, независимо от содержимого. – user207421 18 January 2017 в 13:31

ДА, Эндрю Хейр ответил на переполнение стека по этой ссылке https://stackoverflow.com/a/2486195/4835894 .

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

0
ответ дан Community 19 August 2018 в 08:12
поделиться
  • 1
    Ваш & quot; Нет & quot; как представляется, противоречит §3.10.5 из спецификации языка Java : «Строковый литерал является ссылкой на экземпляр класса String (п. 4.3.1, п. 4.3.3). Более того, строковый литерал всегда ссылается на тот же экземпляр класса String. Это связано с тем, что строковые литералы или, в более общем смысле, строки, которые являются значениями константных выражений (§15.28), являются «интернированными». чтобы совместно использовать уникальные экземпляры, используя метод String.intern. & quot; Проверьте также примеры там – Gennady Vanin Геннадий Ванин 5 April 2013 в 06:00
  • 2
    Даже если они находятся в нескольких (параллельных, одновременных) разных программах, процессах? – Gennady Vanin Геннадий Ванин 5 April 2013 в 06:01
  • 3
    да. если они находятся в нескольких (параллельных, одновременных) разных программах, процесс будет использовать одну и ту же строку для одной и той же JVM не для разных JVM. – AmitG 5 April 2013 в 07:57
  • 4
    Я согласен, что я ошибался в отношении «местоположения памяти». Связанный ответ о StringPool был для меня новостью! – Vorsprung 5 April 2013 в 09:02
  • 5
    первый ответ - ДА. И ссылочные переменные s1 и s2 указывают на одно и то же место строкового объекта в пуле строк. – AmitG 5 April 2013 в 09:07
  • 6
    @AmitG Я согласен, ответ исправлен – Vorsprung 5 April 2013 в 09:26
String s1="Java";
String s2="Java";
My question is whether these two references point to the same memory location  

Dumb citing §3.10.5 Спецификации языка Java :

Строковый литерал является ссылкой на экземпляр класса String ( §4.3.1 , §4.3.3 ).

Кроме того, строковый литерал всегда ссылается на тот же экземпляр класса String. Это связано с тем, что строковые литералы, или, в более общем смысле, строки, которые являются значениями константных выражений ( §15.28 ), «интернированы», чтобы обмениваться уникальными экземплярами, используя метод String.intern.

И прочитайте комментарии к примеру кода там:

Этот пример иллюстрирует шесть пунктов:

  • Литеральные строки в одном и том же класс (§8) в том же пакете (§7) представляют ссылки на один и тот же объект String (§4.3.1).
  • Литеральные строки в разных классах в одном пакете представляют ссылки на один и тот же объект String .
  • Литеральные строки в разных классах в разных пакетах также представляют ссылки на один и тот же объект String.
  • Строки, вычисленные с помощью константных выражений (§15.28), вычисляются во время компиляции, а затем обрабатываются как если они были литералами.
  • Строки, вычисленные путем конкатенации во время выполнения, вновь создаются и, следовательно, различны.
  • Результат явно interni ng вычисленная строка является той же строкой, что и любая ранее существовавшая буквальная строка с тем же содержимым.
5
ответ дан Gennady Vanin Геннадий Ванин 19 August 2018 в 08:12
поделиться

Добавление к другим: новое ключевое слово всегда заставляет создавать новый объект. Если вы объявляете, как показано ниже:

String s1 = "some";
String s2 = "some";

Затем, используя механизм String Pooling, обе ссылки s1 и s2 будут ссылаться на один и тот же объект String со значением «some».

0
ответ дан John Jai 19 August 2018 в 08:12
поделиться

Когда у вас есть

String str1 = new String("BlaBla");  //In the heap!
String str2 = new String("BlaBla");  //In the heap!

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

Но если у вас есть:

String str1 = "BlaBla";        
String str2 = "BlaBla";

, то у вас подразумеваемая конструкция. Литералы двух строк используют одно и то же хранилище, если они имеют одинаковые значения, потому что Java сохраняет память одних и тех же строк! (Строки, имеющие одинаковое значение)

0
ответ дан Maroun 19 August 2018 в 08:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: