Aller au contenu

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 :

  • == est true à cause du String Pool — Java réutilise la même instance
  • equals() est true car 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ême hashCode()

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 de equals()
  • 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() et hashCode()
  • String, Integer et les wrappers ont un comportement particulier à connaître

Voir aussi