2009-12-07 2 views
10

J'ai appris que c'est du diable pour tester l'égalité des chaînes avec == au lieu de String.equals(), parce que chaque chaîne était une référence à son propre objet.Java: Pourquoi l'égalité des chaînes peut-elle être prouvée avec ==?

Mais si j'utiliser quelque chose comme

System.out.println("Hello" == "Hello"); 

il imprime vrai.

Pourquoi?

+1

Jetez un oeil à http://stackoverflow.com/questions/1091045/is-it-good-practice-to-use-java-lang-string-intern. Ils discutent également de ce problème. – ewernli

+0

S'il vous plaît poster un exemple qui montre comment "cela fonctionne maintenant". –

+0

Comme c'est drôle, j'ai inversé {string == null? "": string} - tous mes tests passés, mais quand les chaînes ont commencé à être lues depuis la base de données ... – Stephen

Répondre

26

Ce n'est pas le cas. C'est toujours une mauvaise chose à faire - vous testerez toujours l'égalité de référence au lieu de l'égalité des valeurs. Si vous voyez == "travailler" maintenant, c'est parce que vous avez vraiment des références égales. La raison la plus courante pour voir ce serait probablement dû à interner des littéraux de chaîne, mais qui a été en Java pour toujours:

public class Test 
{ 
    public static void main(String[] args) 
    { 
     String x = "hello"; 
     String y = "hel" + "lo"; // Concatenated at compile-time 
     System.out.println(x == y); // Prints true 
    } 
} 

Ceci est garanti par section 3.10.5 de la spécification du langage Java:

Chaque chaîne literal est une référence (§4.3) à une instance (§4.3.1, §12.5) de la classe String (§4.3.3). La chaîne objets ont une valeur constante. String littéraux ou, plus généralement, les chaînes qui sont les valeurs de constante expressions (§15.28) -sont "internés" donc pour partager des instances uniques, en utilisant la méthode String.intern.

+0

Merci - mais pourquoi cela fonctionne-t-il si j'utilise deux littéraux identiques? – Zeemee

+0

@Mulmoth: Voir le bas de ma réponse (éditée). –

+0

Wow, c'est complètement nouveau pour moi - merci! – Zeemee

3

Cela n'a pas changé. Cependant, le compilateur Java utilise string.intern() pour s'assurer que les chaînes identiques du code source sont compilées avec le même objet String. Si toutefois vous chargez une chaîne à partir d'un fichier ou d'une base de données, ce ne sera pas le même objet, sauf si vous le forcez en utilisant String.intern() ou une autre méthode.

Il est une mauvaise idée, et vous devriez toujours utiliser equals()

+1

L'internalisation manuelle des objets String est risquée car ils ne peuvent jamais être internés ou récupérés. On pourrait facilement consommer toute la mémoire disponible de cette façon. –

+0

@Adriaan - les chaînes internées inaccessibles sont récupérées. Cela a apparemment été implémenté dans JDK 1.2. –

1

Regardez, c'est un concept délicat.

Il y a une différence entre:

// These are String literals 
String a = "Hiabc"; 
String b = "abc"; 
String c = "abc"; 

et

// These are String objects. 
String a = new String("Hiabc"); 
String b = new String("abc"); 
String c = new String("abc"); 

Si vos cordes étaient des objets, à savoir,

String b = new String("abc"); 
String c = new String("abc"); 

Ensuite, deux objets différents auraient été créés dans le pool de chaînes à deux emplacements de mémoire différents et faisant

b == c 

aurait résulté false.

Mais depuis votre String b et String c sont littérales,

b == c 

résultats true. C'est parce que deux objets différents n'ont pas été créés. Et les deux a et b pointent vers la même chaîne dans la mémoire de la pile.

C'est la différence. Vous avez raison, == compare pour l'emplacement de la mémoire. Et c'est la raison,

a.substring(2, 5) == b; // a,substring(2, 5) = "abc" which is at the location of b, and 
b == c // will be true, coz both b and c are literals. And their values are compared and not memory locations. 

Afin d'avoir deux chaînes distinctes avec les mêmes valeurs, mais à différents endroits du String pool et PASstack memory, vous devez créer des objets String comme indiqué ci-dessus.

Ainsi,

a.substring(2, 5) == b; // and 
b == c; // will be false. as not both are objects. Hence are stored on separate memory locations on the String pool. 

vous devez utiliser

a.substring(2, 5).equals(b); 
b.equals(c); 

en cas d'objets.

Questions connexes