Использование '==' вместо .equals для строк Java

Возможный дубликат:
Что заставляет сравнение ссылок (==) работать для некоторых строк в Java?

Я знаю, что об этом уже спрашивали, но, несмотря на рекомендации использовать .equals() вместо == оператора сравнения, я обнаружил, что == работает все время:

String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2); // true

Может ли кто-нибудь привести мне пример сбоя оператора ==?


person Aillyn    schedule 11.09.2010    source источник
comment
Маркос предоставил хороший пример в ответе на вопрос, который вы связали.   -  person Matthew Flaschen    schedule 12.09.2010
comment
Связано: stackoverflow.com/questions/9698260/   -  person Michael Berry    schedule 20.11.2012


Ответы (4)


Это потому что тебе повезло. Оператор == в Java проверяет равенство ссылок: он возвращает true, если указатели совпадают. Он не проверяет равенство содержимого. Идентичные строки, обнаруженные во время компиляции, сворачиваются в один экземпляр String, поэтому он работает с литералами String, но не со строками, сгенерированными во время выполнения.

Например, "Foo" == "Foo" может работать, а "Foo" == new String("Foo") — нет, потому что new String("Foo") создает новый экземпляр String и нарушает любое возможное равенство указателей.

Что еще более важно, большинство Strings, с которыми вы имеете дело в реальной программе, создаются во время выполнения. Пользовательский ввод в текстовые поля генерируется во время выполнения. Сообщения, полученные через сокет, генерируются во время выполнения. Материал, прочитанный из файла, генерируется во время выполнения. Поэтому очень важно использовать метод equals, а не оператор ==, если вы хотите проверить равенство содержимого.

person zneak    schedule 11.09.2010
comment
Небольшое дополнительное примечание: причина, по которой foo == foo действительно работает, заключается в том, что все литеральные строки интернированы download.oracle.com/javase/1.4.2/docs/api/java/lang/ - person Matt Briggs; 11.09.2010

Может ли кто-нибудь привести мне пример сбоя оператора ==?

Пример 1:

String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1 == s2); // false

Пример 2:

Integer a=1000,b=1000;
System.out.println(a == b); // false
person Prasoon Saurav    schedule 11.09.2010
comment
Думаю, это сработает. Но разве строки не являются неизменяемыми? Таким образом, разве они не должны быть интернированы? - person Aillyn; 11.09.2010
comment
Литеральные строки интернированы. - person Bruno Reis; 11.09.2010
comment
Привет == Привет ==› правда. Однако new String(Hello) выделит немного памяти для объекта, и то же самое снова выделит немного памяти в другом месте для другого объекта. Поскольку оператор == сравнивает ссылки, он возвращает false. - person Bruno Reis; 11.09.2010
comment
Маленькие целые числа (-127 .. 127) также интернируются. Таким образом, пример Integer на самом деле вернет true для a = 100 (это деталь реализации, однако я бы не хотел на нее полагаться). - person Thilo; 11.09.2010
comment
@pessimopoppotamus - только строковые литералы интернируются автоматически. Другие экземпляры String интернируются, только если приложение вызывает String.intern() явно. (Это вопрос эффективности: стажировка обходится дорого во многих отношениях.) - person Stephen C; 11.09.2010

Когда вы делаете это, вы фактически создаете строковые литералы:

String s1 = "Hello";
String s2 = "Hello";

Компилятор находит идентичные строковые литералы, а затем оптимизирует, сохраняя один экземпляр в куче и заставляя все переменные в стеке указывать на него. Таким образом, выполнение == вернет true, потому что они указывают на один и тот же адрес памяти.

При этом вы создаете строковые объекты:

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

Создание экземпляра создаст уникальное пространство в куче для каждого из них, а переменные стека будут указывать на эти отдельные местоположения. Таким образом, они будут равны при использовании .equals(), потому что их значения одинаковы, но они не будут равны при использовании ==, поскольку это разные объекты в пространстве кучи памяти.

person Javid Jamae    schedule 11.09.2010

Опытные Java-разработчики редко, если вообще используют new String(String), но проблема возникает и в других случаях. Например:

String hello = "Hello"
String hell = hello.substring(0, 4);
System.err.println("Hell" == hell);  // should print "false".

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

person Stephen C    schedule 11.09.2010
comment
Одной из причин использования y = new String(x) (где x — строка) является разрешение сборки мусора, когда x — подстрока очень большой строки. Если вы просто используете y = x, то очень большая строка не может собирать мусор, пока есть ссылка на y. Если вы используете новую строку (x), создается новая строка, которая не ссылается на исходную большую строку. - person Thomas Mueller; 11.09.2010
comment
Это правда, но по моему опыту это редко бывает необходимо. А если не надо, то это фактически антиоптимизация. - person Stephen C; 11.09.2010