2011-09-26 9 views
6

Powiel możliwe:
If == compares references in Java, why does it evaluate to true with these Strings?
String comparision with logical operator in Javaciąg "==" w java sprawdź odniesienie, dlaczego ten kod zwraca true?

public static void main(String[] args) 
{ 
    String a = "ab"; 
    final String bb = "b"; 
    String b = "a" + bb; 
    System.out.println(a == b); 
} 

dlaczego wydrukować prawda ??

ale

public static void main(String[] args) 
{ 
    String a = "ab"; 
    String bb = "b"; 
    String b = "a" + bb; 
    System.out.println(a==b); 
} 

drukować fałszywe.

Odpowiedz

6

Widzicie wynik dwóch rzeczy pracujących w kombinacji:

  1. Kompilator jest przetwarzanie w czasie kompilacji "a" + bb zamiast wykonywania, ponieważ bb jest final i tak wie, że może to zrobić że. (Są też inne czasy, że to też.)

  2. Wszystkie ciągi generowane przez kompilator są internowane.Aby uzyskać więcej informacji na temat interwencji, zobacz this answer na inne pytanie StackOverflow dotyczące == w Javie.

Więc wynik jest, że a i b punktowe do samo przykład strun, a więc == powraca true.

6

Kompilator oblicza ciąg w czasie kompilacji, ponieważ jest ostateczny i nigdy się nie zmieni.

final String bb = "b"; 
String b = "a" + bb; 

"a" + bb jest oceniana w czasie kompilacji

+0

... co jest pół odpowiedź ... ;-) –

5

Java intern stałe łańcuchowe (ostateczne strings) i literały (utworzyć jedną instancję każdej struny w basenie wewnętrznym), a zatem można uzyskać ten sam przypadek, nawet jeśli jest "stworzony" przez konkatenację.

I jak już wspomniano, optymalizacja kompilatora faktycznie przekształciłaby konkatenację w literał ("ab").

Nigdy nie można w pełni polegać na semantyce String, dlatego należy zawsze używać equals(..).

Edit: wyjaśnienie powyżej zdanie:

Z obiektów == zawsze oznacza, że ​​odniesienia są porównywane i będzie zawsze zwraca true, jeśli oba odniesienia są takie same. Jednak nie zawsze można polegać na uzyskaniu tego samego odwołania do obiektu (jak w przykładzie, w którym proste zmiany w zachowaniu lub w frameworkach takich jak Hibernate itp.), Dlatego zazwyczaj powinieneś używać equals(...).

Oczywiście można użyć ==, jeśli potrzebna jest fizyczna równość (ten sam obiekt) zamiast logicznej równości (ta sama wartość).

Innym przykładem gdzie == miałyby różne wyniki, choć z locical punktu widzenia oba powinny być prawdziwe:

Integer l1 = 0; 
Integer l2 = 0; 
l1 == l2; //most often true, since Integer objects up to 127 are cached 

Integer l1 = 1000; 
Integer l2 = 1000; 
l1 == l2; //most often false, since those are not cached anymore 

Należy zauważyć, że z „najczęściej” To znaczy, że może się to zmienić pomiędzy wersjami Javy (jeśli nie różni się JVM), chociaż nie jest to bardzo prawdopodobne.

+2

* „Nigdy nie można w pełni polegać na ==' semantyki znaków”* Oczywiście można , tak jak możesz z dowolnym ** wzorcem **. '==' będzie "prawdą", jeśli odwołania wskazują na to samo wystąpienie, a "fałsz", jeśli nie. 'equals' jest o czymś zupełnie innym. –

+0

@ T.J. Chodzi mi o to, że nie zawsze wiesz, czy otrzymujesz takie samo odniesienie do ciągu, czy nie, dlatego nie możesz polegać na semantykach. (To samo dotyczy również "Integer"). – Thomas

4

JLS określa to w rozdziale o String Literals:

Każdy łańcuch jest dosłowne odniesienia (§4.3) do instancji (§4.3.1, §12.5) klasy String (§4.3. 3). Obiekty ciągów mają stałą wartość. Literały łańcuchów - lub, bardziej ogólnie, ciągi, które są wartościami wyrażeń stałych (§ 15.28) - są "internowane", aby udostępniać unikalne instancje , używając metody String.intern.

Zatem program kontrolny 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 jednostki kompilacji:

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

daje wynik:

true true true true false true 

BTW: OMM (jdk1.6.0_21, Ubuntu), powyższy kod nie działa le aż położę other.Other.hellopublic a następnie wyprowadza:

true true true true true true 

Aktualizacja: Nie, moja wina. Mój IDE automatycznie dodał final do deklaracji zmiennej lokalnej. Jeśli usunę, że mam:

true true true true false true 
Powiązane problemy