Java — == vs equals()
Principe
En Java :
==compare les références — est-ce le même objet en mémoire ?equals()compare l'égalité logique — est-ce la même valeur ?
Exemple de base
String a = "hello";
String b = "hello";
System.out.println(a == b); // true
System.out.println(a.equals(b)); // true
Les deux sont true, mais pour des raisons différentes :
==esttrueà cause du String Pool — Java réutilise la même instanceequals()esttruecar le contenu est identique
Exemple piégeux
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
new String(...) crée deux objets distincts en mémoire :
==→false(références différentes)equals()→true(contenu identique)
Objets métier sans equals() redéfini
class User {
String name;
User(String name) {
this.name = name;
}
}
User u1 = new User("Ali");
User u2 = new User("Ali");
System.out.println(u1 == u2); // false
System.out.println(u1.equals(u2)); // false
Par défaut, Java hérite de Object.equals(), qui compare comme ==.
Pour une égalité de contenu, il faut redéfinir equals().
Override de equals() et hashCode()
import java.util.Objects;
class User {
String name;
User(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
User u1 = new User("Ali");
User u2 = new User("Ali");
System.out.println(u1 == u2); // false
System.out.println(u1.equals(u2)); // true
Pourquoi hashCode() est obligatoire
Quand on redéfinit equals(), il faut aussi redéfinir hashCode().
Les structures comme HashMap et HashSet utilisent hashCode() pour organiser les objets.
Règle :
si deux objets sont égaux avec
equals(), ils doivent avoir le mêmehashCode()
Ne pas respecter cette règle produit des bugs difficiles à détecter dans les collections.
Pièges fréquents
- croire que
==compare le contenu - croire que
equals()compare toujours le contenu (seulement si redéfini) - oublier
hashCode()après un override deequals() - se laisser tromper par le String Pool avec
==
Questions classiques
Q1
String a = "test";
String b = "test";
System.out.println(a == b);
true — String Pool, même instance.
Q2
String a = new String("test");
String b = new String("test");
System.out.println(a == b);
false — deux objets distincts.
Q3
String a = new String("test");
String b = new String("test");
System.out.println(a.equals(b));
true — même contenu.
Q4
Integer a = 100;
Integer b = 100;
System.out.println(a == b);
true — cache Integer entre -128 et 127.
Q5
Integer a = 200;
Integer b = 200;
System.out.println(a == b);
false — hors cache, deux objets distincts.
À retenir
==→ identité (même référence en mémoire)equals()→ égalité logique (même valeur)- pour les objets personnalisés : redéfinir
equals()ethashCode() String,Integeret les wrappers ont un comportement particulier à connaître