2014-06-23 8 views
5

Uruchomiłem poniższy kod i otrzymałem wyniki wyświetlane w komentarzach. Znam różnice między == i .equals(). Nie rozumiem, dlaczego mój kod w drugiej linii ma inne wyniki niż kod w trzeciej linii.Różnice między "abc" + "de" i "abc" + de (de = "de") w Javie?

String de = "de"; 
// String abcde = "abc" + "de"; // abcde == "abcde" reture true 
    String abcde = "abc" + de; // abcde == "abcde" reture false; 
    System.out.println(); 
    System.out.println(abcde=="abcde"); 
    System.out.println(de=="de"); 

Próbując debugowania to użyłem polecenia -c javap i mam następujący komunikat „kod” dla pierwszego ciągu konkatenacji:

  Code: 
0: ldc  #9; //String de 
2: astore_1 
3: new  #10; //class java/lang/StringBuilder 
6: dup 
7: invokespecial #11; //Method java/lang/StringBuilder."<init>":()V 
10: ldc  #4; //String abc 
12: invokevirtual #12; //Method java/lang/StringBuilder.append:(Ljava/lang 
String;)Ljava/lang/StringBuilder; 
15: aload_1 
16: invokevirtual #12; //Method java/lang/StringBuilder.append:(Ljava/lang 
String;)Ljava/lang/StringBuilder; 
    19: invokevirtual #13; //Method java/lang/StringBuilder.toString:()Ljava/l 
ng/String; 
    22: astore_2 
    23: getstatic  #14; //Field java/lang/System.out:Ljava/io/PrintStream; 
    26: invokevirtual #15; //Method java/io/PrintStream.println:()V 
    29: getstatic  #14; //Field java/lang/System.out:Ljava/io/PrintStream; 
    32: aload_2 
    33: ldc  #16; //String abcde 
    35: if_acmpne  42 
    38: iconst_1 
    39: goto 43 
    42: iconst_0 
    43: invokevirtual #17; //Method java/io/PrintStream.println:(Z)V 
    46: getstatic  #14; //Field java/lang/System.out:Ljava/io/PrintStream; 
    49: aload_1 
    50: ldc  #9; //String de 
    52: if_acmpne  59 
    55: iconst_1 
    56: goto 60 
    59: iconst_0 
    60: invokevirtual #17; //Method java/io/PrintStream.println:(Z)V 
    63: return 

a wyjście dla drugiego połączonego łańcucha znaków:

nie jestem tak obeznany z tym „kodu” i nie widzę żadnego powodu, dla którego istnieje te różnice. Czy ktoś mógłby wyjaśnić, dlaczego te różnice się zdarzają?

Powiązane post

+8

Jakie jest aktualne pytanie? (Zakładam, że już wiesz, że '==' porównuje ciąg * referencje *, a nie ciąg * treść *)? – NPE

+1

Zobacz metodę 'String.equals (....)', to NIE jest to samo co '==' operator ... – vikingsteve

+1

Aby zrozumieć "Ten kod" ... można odnieść się do dokumentu [zestawu instrukcji JVM] (http : //docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html). –

Odpowiedz

11

"Problem" polega na tym, że kompilator jest dla ciebie zbyt inteligentny. Kiedy widzi "abc" + "de", natychmiast łączy to z dosłownym "abcde". Ale gdy widzi "abc" + de, to nie jest dozwolone (zgodnie z regułami Java), aby "zoptymalizować" to do literału, ale musi zamiast tego zaimplementować funkcję +, tworząc nowy obiekt String.

Literały łańcuchowe są zawsze traktowane jako napisy internowane, więc == będzie na nich działał.

+1

Czy masz na myśli, że "abc" + "de" jest częścią puli stringów, zanim program naprawdę zacznie działać? – Tony

+3

@Tony - Kompilator został zaprojektowany w taki sposób, że instrukcja typu 'String a =" abc "+" de ";' zostanie skompilowana jako 'String a =" abcde ";'. Jest to zgodne z projektem, aby umożliwić łączenie wieloliniowych literałów łańcuchowych z '+' i innymi podobnymi rzeczami. –

+1

Dzięki za cierpliwość. Jeszcze jedno pytanie: kiedy pula stała jest ładowana do JVM lub pamięci. Dzięki. – Tony

3

Problemem nie jest to zrobić z +, jest to, że jesteś porównywania ciągów z ==.

Krótka odpowiedź: użyć "string".equals("string2")

w Javie == jest referencyjna wynosi w przypadku korzystania z obiektów (takich jak ciągi); "czy te dwie nazwy wskazują na ten sam obiekt w pamięci?"

Java ma pulę wspólnych ciągów, których używa zamiast tworzenia nowego obiektu za każdym razem (co nie jest problemem, ponieważ ciągi znaków są niezmienne), więc problem z prawdą/fałszem sprowadza się do tego, czy kompilator jest wystarczająco inteligentny rozpoznać, że te dwa łańcuchy byłyby takie same lub nie, a zatem może on wykorzystywać ten sam obiekt. Nie polegaj na tym.

+0

Przepraszam, że wprowadzam w błąd. Zobacz moją edycję. – Tony

2
String de = "de"; // "de" is set during compile time and placed in the "String Pool". 
// String abcde = "abc" + "de";// abcde == "abcde" reture true -- > String reference abcde will be set to "abcde" during compilation itself. and "abcde" will be placed in the String Pool. 
    String abcde = "abc" + de;   // abcde == "abcde" reture false; abcde will not be set during compilation as the value of reference de will be resolved during runtime. 
    System.out.println(); 
    System.out.println(abcde=="abcde");// false as --> String literal "abcde" on String pool != String Object "abcde" on heap. 
    System.out.println(de=="de");// true--> de points to "de" on String pool 
1

To artefakt kompilatora Java. Jak powinieneś wiedzieć, == porównuje odniesienia do obiektów, nie porównuje ich zawartości.

Kompilator Java interns nagie ciągi widoczne w kodzie źródłowym. Dlatego właśnie "x"=="x", ponieważ istnieje tylko jedna kopia ciągu "x", internowana z kodu źródłowego, ale odczytywanie w łańcuchu z pliku, którego wartość to "x", nie będzie == internowane "x", ponieważ nie jest to ten sam obiekt.

Kompilator Java jest także sprytny w kwestii operatora + w Strings. Będzie wewnętrznie konwertować var+"x" na new StringBuffer().append(var).append("x").toString(). Ale będzie także łączyć łańcuchy i stawiać je jako kolejny łańcuch, np. "abc"+"de" spowoduje internowany ciąg "abcde", a nie new StringBuffer().append("abc").append("de").toString().

Powiązane problemy