Будут ли сохранены две строки с одинаковым содержимым в одной и той же ячейке памяти?
Это вопрос, который я получил в интервью.
У меня две строки, определенные как
String s1="Java";
String s2="Java";
Мой вопрос заключается в том, указывают ли эти две ссылки на одно и то же место памяти. В общем случае, когда мы создаем идентичные строки (без нового ключевого слова), содержимое сохраняется в памяти только один раз, и все объекты String с одним и тем же содержимым просто ссылаются на одно и то же место, не сохраняя избыточную строку "Java"? Хэш-коды s1 и s2 совпадают. Но являются ли хэш-коды зависимыми непосредственно от местоположения памяти объекта?
Ответы
Ответ 1
Процесс объединения одинаковых строк называется "interning" и уже много лет выполняется множеством компиляторов языка, но не всегда. Ответ на этот вопрос, особенно в том виде, в котором он расширился: Геннадий Ванин - Новосибирск, зависит от языка и реализации компилятора. Для Java все константные строки интернированы в соответствии с требованиями Java Language Specification. Но это только постоянные строковые выражения и только тогда, когда они скомпилированы в одно и то же время. Если у вас есть две строки Java, достаточно разделенные во времени и пространстве (например, скомпилированные в отдельные файлы JAR), они не будут одним и тем же объектом. Точно так же динамически созданные строки Java (например, вывод различных методов toString()
) не будут интернированы, если метод специально не запрашивает его через String.intern()
. И да, все использование интернированной строки будет разделять одни и те же ячейки памяти - что большая часть того, почему строки интернированы в первую очередь.
Что касается других языков, это вопрос большой, но со всей информацией в этих ответах я уверен, что вы можете исследовать его в Интернете. Достаточно сказать, что нет универсального соглашения о том, как это должно быть сделано.
Ответ 2
Когда компилятор оптимизирует ваши строковые литералы, он видит, что оба s1 и s2 имеют одинаковое значение, и поэтому вам нужно только один строковый объект. Это безопасно, потому что String неизменна в Java.
String s1="Java";
String s2="Java";
System.out.println(s1== s2);
Это дает результат true
, потому что s1
и s2
указывает на один и тот же объект.
String Pool - это механизм, в котором вся уже определенная строка хранится в некотором "пуле" и перед созданием нового компилятора объекта String проверяет, определена ли такая строка.
Ответ 3
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).
Кроме того, строковый литерал всегда ссылается на тот же экземпляр класса Строка. Это потому, что строковые литералы - или, в более общем смысле, строки которые являются значениями константных выражений (§15.28) - являются "интернированный", чтобы обмениваться уникальными экземплярами, используя метод String.intern.
И прочитайте комментарии к примеру кода:
Этот пример иллюстрирует шесть пунктов:
-
Литеральные строки в одном классе (§8) в том же пакете (§7) представляют ссылки на один и тот же объект String (§4.3.1).
-
Литеральные строки в разных классах в одном пакете представляют ссылки на один и тот же объект String.
-
Литеральные строки в разных классах в разных пакетах также представляют ссылки на один и тот же объект String.
-
Строки, вычисленные постоянными выражениями (§15.28), вычисляются во время компиляции, а затем обрабатываются так, как если бы они были литералами.
-
Строки, вычисленные путем конкатенации во время выполнения, создаются и поэтому различаются.
-
Результат явного интернирования вычисленной строки является той же строкой, что и любая ранее существовавшая буквальная строка с тем же содержимым.
Ответ 4
Пример.
Первый пример
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 проверяет, существует ли строка или нет. Если мы создадим объект второй строки с использованием нового и имеем разный контент, тогда он создает объект и назначает другую ссылку, а в случае Если мы не создаем объект с использованием нового и не будем иметь один и тот же контент, тогда его назначение будет иметь ту же ссылку, что и первая строка,.
Ответ 5
Java использует механизм с именем StringPool. Это означает, что каждый раз, когда создается новая строка, имеющая значение, равное строке, которая уже была создана. Пример:
String s1 = "Java"; Строка s2 = "Java";
java не будет создавать новый объект, равный исходному, но второй s2
будет просто указывать на то же место в пуле строк. Лучшее объяснение можно найти здесь.
Ответ 6
String s1="Java";
String s2="Java";
Указывают ли они на одну и ту же ячейку памяти?
Я изначально сказал "нет", но в приведенном выше случае см. ответ StringPool, упомянутый ниже, на самом деле да..
", когда мы создаем идентичные строки (без нового ключевого слова), делает содержимое сохраняется в памяти только один раз, и все объекты String с тем же содержимым просто ссылаются на одно и то же место"
... вид см. подробный ответ в вопросе "Строки Java и StringPool"
"Хэш-коды s1 и s2 одинаковы. Но зависят ли хэш-коды непосредственно в ячейке памяти объекта?"
Нет, хэш-коды зависят от содержимого строки
Ответ 7
Добавление к другим:
новое ключевое слово всегда заставляет создавать новый объект.
Если вы заявляете, как показано ниже:
String s1 = "some";
String s2 = "some";
Затем, используя механизм String Pooling, обе ссылки s1 и s2 будут ссылаться на один и тот же объект String со значением "some".
Ответ 8
Если у вас
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 сохраняет память одних и тех же строк! (Строки, имеющие одинаковое значение)
Ответ 9
String s1="Java";
String s2="Java";
обе точки к одному и тому же объекту. подробнее нажмите здесь
Ответ 10
ДА,
Andrew Hare ответил на переполнение стека в этой ссылке fooobar.com/info/18476/....
В принципе, пул-пул строк позволяет среде выполнения сохранять память, сохраняя неизменяемые строки в пуле, чтобы области приложения могли повторно использовать экземпляры общих строк вместо создания нескольких экземпляров.