2009-07-10 3 views
30

EDIT Спасибо за оперативные ответы. Посмотрите, каков настоящий вопрос. На этот раз я сделал это смело.Когда "" == s является ложным, но "". Равны (равно) равен

Я понимаю разницу между == и .equals. Таким образом, это не мой вопрос (я на самом деле добавил некоторый контекст для этого)


Я выполнение проверки ниже для пустых строк:

if("" == value) { 
    // is empty string 
} 

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

Так что исправление для тех ситуаций, было

if("".equals(value)) { 
    // which returns true for all the empty strings 
} 

Я в порядке с этим. Это понятно.

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

Так что вопрос:


В каких ДРУГИЕ обстоятельства:

"" == value // yields false 

и

"".equals(value) // yields true 

Для местного применения автономного?

Я уверен, новый String() не используется в коде.

И единственный способ ссылки строка может быть «», потому что это в настоящее время назначается «» непосредственно в коде (или то, что я думал), как в:

String a = ""; 
String b = a; 

assert "" == b ; // this is true 

Как-то (после прочтения кода более у меня есть ключ были созданы) два различных объектные ссылки пустой строки, я хотел бы знать, как

Больше в строке jjnguys ответа:

Byte!

EDIT: Заключение

Я нашел причину.

После предложения jjnguy я смог смотреть разными глазами на код.

Виновный метод: StringBuilder.toString()

A new String object is allocated and initialized to contain the character sequence currently represented by this object.

Doh ...

StringBuilder b = new StringBuilder("h"); 
    b.deleteCharAt(0); 
    System.out.println("" == b.toString()); // prints false 

Тайна решена.

В коде используется StringBuilder для обработки постоянно растущей строки. Оказывается, что в какой-то момент кто-то сделал:

public void someAction(String string) { 
     if("" == string) { 
      return; 
     } 

     deleteBankAccount(string); 
} 

и использовать

someAction(myBuilder.toString()); // bug introduced. 

P.S. Я читал слишком много CodingHorror в последнее время? Или почему я чувствую необходимость добавить некоторые забавные фотографии животных здесь?

+4

if (value! = Null && value.length == 0) {...}, и вы должны использовать equals потому, что == для объектов сравнивает ссылки, т. Е. Являются ли они одним и тем же объектом. Хотя во время компиляции Java находит идентичные строки и заставляет их использовать одну и ту же ссылку (строки неизменяемы), во время выполнения легко создавать пустые строки, которые имеют разные ссылки. – JeeBee

+0

Как мой ответ предлагает ... забыть, что вы «думали». Если вы хотите проверить, имеет ли что-то то же значение, что и пустая строка, тогда используйте equals. Вы пытаетесь зависеть от компилятора, который интернирует ваши строки, что указывает Джош Блох, это не инструмент для программистов :-). Смотри ниже. – Tom

+0

Несколько ответов теперь показывают простые манипуляции с строками, которые дают разные объекты String нулевой длины. Сети и доброта не имеют ничего общего с этими ответами. – djna

ответ

24
String s = ""; 
String s2 = someUserInputVariale.toLowercase(); // where the user entered in "" 

Что-то подобное могло бы привести к ошибке s == s2.

Множество порогов кода создать новый Strings, не подвергаясь вызову new String().

+0

В любое время, когда строка генерируется/создается/управляется во время выполнения, у нее есть потенциал. Я предполагаю, что виртуальная машина может создать новую строку для пула строк по своему усмотрению, хотя для оптимизации было бы лучше использовать существующую строку. – user101884

+0

Правописание для словарей ... – jjnguy

+12

Нет, мне это нравится. «Мы, программисты Java, даже не знаем, как SPELL optimyz ... optimo ... look, JIT делает это для нас в порядке?» –

2

Вы должны попробовать рассмотреть вопрос об String.length() == 0.

+0

Я бы тоже предложил это, если строка не может быть нулевой. ;) –

+0

Это не отвечает на его вопрос ... – jjnguy

7

Ожидаете ли вы "abcde".substring(1,2) и "zbcdefgh".substring(1,2), чтобы получить тот же объект String?

Они обе дают «равные» подстроки, извлеченные из двух разных строк, но представляется вполне разумным, что tehy - разные объекты, поэтому == видит их как разные.

Теперь рассмотрим, когда подстрока имеет длину 0, substring(1, 1). Он дает строку с нулевой длиной, но неудивительно, что "abcde".substring(1,1) - это другой объект от "zbcdefgh".substring(1,2), и, следовательно, по крайней мере один из них является другим объектом из «".

+1

Я не думаю, что эта аналогия действительно проясняет что-то –

+2

Я делаю. В нем говорится, что даже если нет явных вызовов «новой строки», много кода все еще создает новые строки ... substring, toUpperCase и т. Д. – erickson

+0

Я думаю, что это хороший ответ. очевидно, можно было бы ожидать, что == возвращает false, но .equals дает true. И это то, что спрашивал на самом деле, а не «какая разница между == и равна», что большинство других ответили ему –

0

Почему бы не использовать:

if (value != null && value.length == 0) { 
    // do stuff (above could be "== null ||" 
} 

Вы должны использовать equals() потому == объектов сравнивает ссылки, то есть, они же объект. Хотя во время компиляции Java находит идентичные строки и заставляет их использовать одну и ту же ссылку (строки неизменяемы), во время выполнения легко создавать пустые строки, которые имеют разные ссылки, где == fail для вашего типичного намерения equals().

3

Как я понимаю, при компиляции кода Java в байт-код или во время работы программы одни и те же строки в большинстве случаев будут ссылаться на один и тот же объект для сохранения памяти. Поэтому иногда вы избегаете == сравнения строк. Но это оптимизация компилятора, на которую нельзя положиться.

Но иногда случается, что компилятор решает не выполнять эту оптимизацию или нет возможности для программы видеть, что строки одинаковы, и из-за неожиданного сбоя проверки, поскольку вы полагаетесь на некоторую базовую оптимизацию voodoo, который зависит от реализации jvm, который вы используете, и так далее.

Таким образом, использование equals всегда является хорошей вещью. Для пустых строк существуют другие возможности, такие как сравнение с длиной == 0 или если вам не нужна обратная совместимость, существует string.empty().

10

Если вы можете взять в руки эту книгу Java Puzzlers Джошуа Блоха и Нил Gafter, и смотреть на головоломки 13, «Ферма животных» ... он имеет большой совет по этому вопросу. Я собираюсь скопировать некоторые соответствующий текст:

«Вы можете быть в курсе, что во время компиляции константы типа String являются интернированы [JLS 15,28] Другими словами, любые два константные выражения типа String, обозначающие. такая же последовательность символов представлена ​​идентичными объектными ссылками ... Ваш код должен редко, если вообще когда-либо, зависеть от интернирования строковых констант. Interning был разработан исключительно для уменьшения объема памяти виртуальной машины, а не как инструмента для программистов ... При сравнении ссылок на объекты, вы должны использовать equals метод, отличный от == оператор, если вам не нужно сравнивать идентификацию объекта, а не стоимость ».

Это из приведенной выше ссылки, о которой я упоминал ... страницы 30 - 31 в моей книге.

+2

Другими словами ... использование равно, потому что это то, что вы имеете в виду ... и это то, что вы имеете в виду. – Tom

20
"" == value // yields false 

и

"".equals(value) // yields true 

любое время значение переменной value не был интернирован. Это будет иметь место, если значение вычисляется во время выполнения. См JLS section 3.10.5 String Literals, например, иллюстрирующий это:

Thus, the test program consisting of the compilation unit (§7.3):

package testPackage; 
class Test { 
    public static void main(String[] args) { 
     String hello = "Hello", lo = "lo"; 
     System.out.print((hello == "Hello") + " "); 
     System.out.print((Other.hello == hello) + " "); 
     System.out.print((other.Other.hello == hello) + " "); 
     System.out.print((hello == ("Hel"+"lo")) + " "); 
     System.out.print((hello == ("Hel"+lo)) + " "); 
     System.out.println(hello == ("Hel"+lo).intern()); 
    } 
} 
class Other { static String hello = "Hello"; } 

and the compilation unit:

package other; 
public class Other { static String hello = "Hello"; } 

produces the output:

true true true true false true 

This example illustrates six points:

  • Literal strings within the same class (§8) in the same package (§7) represent references to the same String object (§4.3.1).
  • Literal strings within different classes in the same package represent references to the same String object.
  • Literal strings within different classes in different packages likewise represent references to the same String object.
  • Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals.
  • Strings computed at run time are newly created and therefore distinct.
  • The result of explicitly interning a computed string is the same string as any pre-existing literal string with the same contents.
0

javadoc для String.intern() имеет хороший комментарий на == VS. .equals().

В документации также разъясняется, что каждый строковый литерал равен intern 'd.

public String intern()

Returns a canonical representation for the string object.

A pool of strings, initially empty, is maintained privately by the class String.

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.

All literal strings and string-valued constant expressions are interned. String literals are defined in §3.10.5 of the Java Language Specification

Returns: a string that has the same contents as this string, but is guaranteed to be from a pool of unique strings.

0

Если вы используете Google поиск коды, вы можете найти много мест, где люди делают эту же ошибку: google for file:.java \=\=\ \"\" Конечно, это может быть правильной идиома в тщательно контролируемых условиях, но, как правило, его просто ошибка.

+0

Да. Что ж, для приложений, использующих сеть, довольно часто приходится терпеть неудачу, но для автономного кода это очень странно. Запрос google хорош !! :) – OscarRyz

+0

К сожалению, ссылка мертва – ComputerDruid

Смежные вопросы