Строковое равенство против равенства местоположения - PullRequest
7 голосов
/ 27 февраля 2009
String s1 = "BloodParrot is the man";  
String s2 = "BloodParrot is the man";  
String s3 = new String("BloodParrot is the man");  

System.out.println(s1.equals(s2));
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1.equals(s3));

// вывод
правда
правда
ложь
правда

Почему не все строки имеют одинаковое расположение в памяти, если все три имеют одинаковое содержимое?

Ответы [ 6 ]

15 голосов
/ 27 февраля 2009

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

Если вы добавите строку

s3 = s3.intern();

к вашему коду сразу после создания s3, вы увидите разницу в вашем выводе.

См. Еще несколько примеров и более подробное объяснение .

Это, конечно, поднимает очень важную тему: когда использовать ==, а когда использовать метод equals в Java. Вы почти всегда хотите использовать equals при работе со ссылками на объекты. Оператор == сравнивает эталонные значения, которые почти никогда не соответствуют тому, что вы хотите сравнить. Знание разницы помогает вам решить, когда уместно использовать == или equals.

3 голосов
/ 27 февраля 2009

Вы явно вызываете new для s3, и это оставляет вас с новым экземпляром строки.

2 голосов
/ 27 февраля 2009

Создание String на самом деле быстрый процесс. Попытка найти ранее созданный String будет намного медленнее.

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

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

1 голос
/ 27 февраля 2009

Существует метод, называемый String.intern, который, по сути, берет все одинаковые строки и помещает их в хеш-таблицу (я в некотором роде лгу, но для этого важна концепция, а не реальность) ,

String s1 = "BloodParrot is the man";  
String s2 = "BloodParrot is the man";  
String s3 = new String("BloodParrot is the man").intern();  

System.out.println(s1.equals(s2));
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1.equals(s3));

должно быть, чтобы все они были "правдивыми". Это потому, что (и я снова немного вру, но это важно только для концепции, а не для реальности) String s1 = "BloodParrot - это человек"; сделано что-то вроде String s1 = "BloodParrot это человек" .intern ();

1 голос
/ 27 февраля 2009

Почему не все строки имеют одинаковое расположение в памяти, если все три имеют одинаковое содержимое?

Потому что они разные строки с одинаковым содержанием!

1 голос
/ 27 февраля 2009

Новое ключевое слово всегда создает новую строку.

Подробнее здесь .

...