Dans les entretiens techniques, on nous fréquemment demande quelle est la différence entre l'opérateur "==" et la méthode equals() pour les types de référence. La réponse habituelle est que "==" compare les adresses mémoire tandis que equals() compare le contenu. Mais quels sont les mécanismes sous-jacents de ces comportements ?
Prenons l'exemple de la classe String. Pour vérifier l'égalité de deux chaînes de caractères, nous utilisons généralement la méthode equals() :
String chaine = "exemple";
String autreChaine = new String("exemple"); // allocation d'un nouvel espace mémoire
System.out.println(autreChaine == chaine); // false
System.out.println(autreChaine.equals(chaine)); // true
Après une analyse approfondie, j'ai découvert que la méthode equals() est définie dans la classe Object, la classe racine de Java dont toutes les classes héritent.
La classe String, en tant que sous-classe de Object, redéfinit donc naturellement la méthode equals() pour adapter son comportement. La version originale dans Object compare en réalité les adresses mémoire.
Voici le code source de la méthode equals() dans la classe String :
public boolean equals(Object autreObjet) {
// Vérification si les références pointent vers le même objet
if (this == autreObjet) {
return true;
}
// Vérification si le paramètre est de type String
if (autreObjet instanceof String) {
// Conversion de type
String autreChaine = (String)autreObjet;
int longueur = donnees.length;
// Comparaison des longueurs
if (longueur == autreChaine.donnees.length) {
// Comparaison des caractères si les longueurs sont identiques
char tab1[] = donnees;
char tab2[] = autreChaine.donnees;
int index = 0;
// Boucle pour comparer chaque caractère
while (longueur-- != 0) {
if (tab1[index] != tab2[index])
return false;
index++;
}
// Si les longueurs et le contenu sont identiques
return true;
}
}
// Aucune condition n'est remplie
return false;
}
Cette méthode commence par vérifier si les références sont identiques. Si c'est le cas, le contenu est forcément le même et elle retourne true. Sinon, elle vérifie si le paramètre est de type String. Si c'est le cas, elle effectue une conversion de type, puis compare les longueurs des chaînes. Si elles diffèrent, elle retourne false immédiatement. Si elles sont identiques, elle procède à une comparaiosn caractère par caractère des tableaux internes.
Nous comprenons ainsi comment equals() implémente la comparaison de contenu au niveau bas.
Cette compréhension nous permet de redéfinir la méthode equals() dans nos propres classes lorsque nous souhaitons comparer le contenu plutôt que les références.