Gdy ""= = S jest false ale"".equals(s) is true

Edytuj Dzięki za szybką odpowiedź. Proszę zobaczyć, jakie jest prawdziwe pytanie. Tym razem zrobiłem to odważnie.

Rozumiem różnicę między = = i .równi. Tak więc, to nie jest moje pytanie (w rzeczywistości dodałem jakiś kontekst dla tego)


Wykonuję walidację poniżej dla pustych łańcuchów:

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

W przeszłości podczas pobierania wartości z db lub deserializacji obiektów z innego węzła, ten test nie powiódł się, ponieważ dwie instancje łańcuchowe były rzeczywiście różnymi odniesieniami do obiektów, chociaż zawierały te same dane.

Więc rozwiązaniem dla tych sytuacji było

if( "".equals( value ) ) {
   // which returns true for all the empty strings
}
Nie przeszkadza mi to. To zrozumiałe.

Dzisiaj stało się to po raz kolejny, ale mnie to zastanowiło, ponieważ tym razem aplikacja jest bardzo małą samodzielną aplikacją, która w ogóle nie korzysta z sieci , więc żaden nowy ciąg nie jest pobierany z bazy danych ani dezeryzowany z innego węzeł.

Więc pytanie brzmi:


W którym Inne okoliczności:

"" == value // yields false 

I

"".equals( value ) // yields true

Do lokalnej samodzielnej aplikacji?

Jestem prawie pewien, że new String () nie jest używany w kodzie.

I jedynym sposobem na odniesienie do łańcucha może być ""Jest to, że jest przypisany "" bezpośrednio w kodzie (lub tak myślałem) jak w:

String a = "";
String b = a;

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

Jakoś (po przeczytaniu kodu więcej mam clue) powstały dwa różne odwołania do pustych obiektów string, chciałbym wiedzieć Jak

Więcej w linii jjnguys odpowiedź:

Bajt!

EDIT: Conclusion

Znalazłem powód.

Po sugestii jjnguy mogłem spojrzeć innym okiem na kod.

The guilty method: StringBuilder.toString ()

nowy obiekt String jest przydzielany i inicjowany tak, aby zawierał sekwencję znaków obecnie reprezentowany przez ten obiekt.

Doh!...
    StringBuilder b = new StringBuilder("h");
    b.deleteCharAt( 0 );
    System.out.println( "" == b.toString() ); // prints false
Tajemnica rozwiązana.

Kod używa Stringbuildera do radzenia sobie z ciągle rosnącym ciągiem znaków. Okazuje się, że w pewnym momencie ktoś to zrobił:

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

       deleteBankAccount( string );
 }

I używać

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

P. S. czy ostatnio za dużo czytam CodingHorror? Albo dlaczego czuję potrzebę dodania tutaj śmiesznych zdjęć zwierząt?

Author: Bill the Lizard, 2009-07-10

10 answers

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

Coś takiego spowodowałoby s == s2 ocenę na false.

Mnóstwo kodu tworzy nowe Strings bez wystawiania wywołania na new String().

 25
Author: jjnguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-10 19:01:59
"" == value // yields false

I

"".equals( value ) // yields true

Kiedykolwiek wartość zmiennej value nie została internowana. Będzie tak, jeśli wartość jest obliczana w czasie wykonywania. Zobacz JLS sekcja 3.10.5 literały łańcuchowe na przykład kod ilustrujący to:

Tak więc program testowy składający się z jednostki kompilacji (§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"; }

I jednostka kompilacji:

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

Produkuje wyjście:

true true true true false true

Ten przykład ilustruje sześć punktów:

  • dosłowne łańcuchy w tej samej klasie (§8) w tym samym pakiecie (§7) reprezentują odniesienia do tego samego obiektu String (§4.3.1).
  • dosłowne łańcuchy w różnych klasach w tym samym pakiecie reprezentują odniesienia do tego samego obiektu String.
  • dosłowne łańcuchy w różnych klasach w różnych pakietach podobnie reprezentują odniesienia do tego samego obiektu String.
  • Łańcuchy obliczane przez wyrażenia stałe (§15.28) są obliczane w czasie kompilacji, a następnie traktowani jak literaci.
  • Łańcuchy obliczane w czasie wykonywania są nowo tworzone, a zatem odrębne.
  • wynik jawnego internowania obliczonego ciągu jest tym samym łańcuchem, co każdy wcześniej istniejący literalny łańcuch o tej samej zawartości.
 21
Author: Bill the Lizard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-28 17:01:04

Jeśli możesz chwycić książkęJava Puzzlers autorstwa Joshuy Bloch i Neala Gaftera, i spojrzeć na puzzle 13, "Animal Farm"... ma świetne rady w tej sprawie. Mam zamiar skopiować jakiś odpowiedni tekst:

"Możesz być świadomy, że stałe czasu kompilacji typu String internowane [JLS 15.28]. Innymi słowy, dowolne dwa stałe wyrażenia typu String, które wyznaczają ten sam ciąg znaków, są reprezentowane przez identyczne odwołania do obiektów... Twój kod rzadko, jeśli w ogóle, zależy od internowania stałych łańcuchów.[14]} Interning został zaprojektowany wyłącznie w celu zmniejszenia ilości pamięci maszyny wirtualnej, a nie jako narzędzie dla programistów... Porównując odniesienia do obiektów, należy użyć metody equals zamiast operatora == , chyba że trzeba porównać tożsamość obiektu zamiast wartości."

To z powyższego odniesienia, o którym wspomniałem... strony 30 - 31 w mojej książce.

 10
Author: Tom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-10 19:05:24

Czy spodziewasz się, że "abcde".substring(1,2) i "zbcdefgh".substring(1,2) uzyskają ten sam obiekt String?

Obie dają" równe " sub-struny wyodrębnione z dwóch różnych strun, ale wydaje się całkiem rozsądne, że tehy są różnymi obiektami, więc = = postrzega je jako różne.

Rozważmy teraz, kiedy podłańcuch ma długość 0, substring(1, 1). Daje ciąg o zerowej długości, ale nic dziwnego, że {[3] } jest innym obiektem od "zbcdefgh".substring(1,2), a więc przynajmniej jeden z nich jest innym obiektem od"".

 7
Author: djna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-10 19:14:00

Jak rozumiem podczas kompilacji kodu Javy do bajtkodu lub podczas uruchamiania programu te same ciągi znaków będą odwoływane do tego samego obiektu w większości przypadków, aby zapisać pamięć. Więc czasami ujdzie ci to na sucho = = porównania ciągów. Ale jest to optymalizacja kompilatora, na której nie możesz polegać.

Ale czasami zdarza się, że kompilator decyduje się nie robić tej optymalizacji lub nie ma możliwości, aby program zobaczył, że ciągi są takie same i nagle sprawdzić zawiedzie, Ponieważ polegasz na jakiejś podstawowej optymalizacji voodoo, która zależy od implementacji jvm, którego używasz i tak dalej.

Więc używanie równości jest zawsze dobrą rzeczą do zrobienia. Dla pustych łańcuchów istnieją inne możliwości, takie jak porównywanie z długością = = 0 lub jeśli nie zależy ci na kompatybilności wstecznej, istnieje string.empty().

 3
Author: Janusz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-10 19:02:11

Powinieneś spróbować rozważyć String.length() == 0.

 2
Author: Paul Sonier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-10 19:40:58
 0
Author: artlung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-10 19:02:35

The javadoc for String.intern() ma dobry komentarz na temat == vs. .equals().

Dokumentacja wyjaśnia również, że każdy literał ciągu To intern ' d.

Public String intern ()

Zwraca kanoniczną reprezentację dla obiektu string.

Pula łańcuchów, początkowo pustych, jest utrzymywana prywatnie przez klasę String.

Gdy wywołana jest metoda intern, jeśli Pula zawiera już ciąg równy temu obiektowi Łańcuchowemu jako określone przez równe (obiekt) metoda, następnie ciąg z puli jest zwrócony. W przeciwnym razie ten ciąg znaków obiekt jest dodawany do basenu i odniesienie do tego obiektu String jest zwrócony.

Wynika z tego, że dla dowolnych dwóch ciągów s i t, s. intern () = = t.intern () jest true wtedy i tylko wtedy, gdy s. równa się (t) jest prawda.

Wszystkie ciągi literalne i ciągi o wartości wyrażenia stałe są internowane. Literały ciągów są zdefiniowane w §3.10.5 języka Java Specyfikacja

Zwraca: łańcuch, który ma ten sam zawartość jako ten ciąg znaków, ale jest gwarantowana z puli unikalnych struny.

 0
Author: Alex B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-10 19:15:30

Jeśli korzystasz z Google code search, możesz znaleźć wiele miejsc, w których ludzie popełniają ten sam błąd: google dla pliku:.java \=\=\ \"\" oczywiście może to być poprawny idiom w starannie kontrolowanych okolicznościach, ale zazwyczaj jest to tylko błąd.

 0
Author: Trevor Harrison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-10 21:11:14

Dlaczego nie używać:

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

Powinieneś użyć equals() Ponieważ == dla obiektów porównuje odniesienia, tzn. czy są one tym samym obiektem. Podczas gdy w czasie kompilacji Java znajduje identyczne ciągi znaków i sprawia, że mają te same odniesienia( ciągi znaków są niezmienne), w czasie wykonywania łatwo jest tworzyć puste ciągi znaków, które mają różne odniesienia, gdzie = = zawodzi dla typowej intencji equals().

 0
Author: JeeBee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-10 13:40:12