Le rôle de l'opérateur ==
Dans Java, l'opérateur == est utilisé pour comparer deux variables, mais son comportement varie selon le type de données.
Pour les huit types primitifs (byte, short, int, long, double, float, boolean, char), == vérifie si les valeurs numériques sont identiques, stockées directement dans la pile.
byte premierOctet = 5, secondOctet = 5;
short premierCourt = 10, secondCourt = 10;
int premierEntier = 20, secondEntier = 20;
long premierLong = 30L, secondLong = 30L;
double premierDouble = 1.5, secondDouble = 1.5;
float premierFlottant = 2.5f, secondFlottant = 2.5f;
boolean premierBooleen = false, secondBooleen = false;
char premierCaractere = 'A', secondCaractere = 'A';
System.out.println("byte : premierOctet == secondOctet " + (premierOctet == secondOctet));
System.out.println("short : premierCourt == secondCourt " + (premierCourt == secondCourt));
System.out.println("int : premierEntier == secondEntier " + (premierEntier == secondEntier));
System.out.println("long : premierLong == secondLong " + (premierLong == secondLong));
System.out.println("double : premierDouble == secondDouble " + (premierDouble == secondDouble));
System.out.println("float : premierFlottant == secondFlottant " + (premierFlottant == secondFlottant));
System.out.println("boolean : premierBooleen == secondBooleen " + (premierBooleen == secondBooleen));
System.out.println("char : premierCaractere == secondCaractere " + (premierCaractere == secondCaractere));
Pour les types de référence, == compare les adresses mémoire des objets, c'est-à-dire si les deux variables pointent vers la même instacne dans le tas.
Object instance1 = new Object();
Object instance2 = instance1;
Object instance3 = new Object();
System.out.println("Object : instance1 == instance2 " + (instance1 == instance2));
System.out.println("Object : instance1.equals(instance2) " + (instance1.equals(instance2)));
System.out.println("Object : instance1 == instance3 " + (instance1 == instance3));
System.out.println("Object : instance1.equals(instance3) " + (instance1.equals(instance3)));
L'implémentation par défaut de equals dans la classe Object utilise également == pour la comparaison.
Le rôle de la méthode equals
La méthode equals est définie dans la classe Object et est destinée aux objets. Par défaut, elle compare les références, mais elle peut être redéfinie pour offrir une logique de comparaison personnalisée.
Considérons les chaînes de caractères, qui sont des objets en Java. La JVM optimise la mémoire avec un pool de chaînes (string pool), où les littéraux identiques partagent la même adresse.
String chaineA = "test", chaineB = "test";
String chaineC = new String("test");
String chaineD = new String("test");
System.out.println("String : chaineA == chaineB " + (chaineA == chaineB));
System.out.println("String : chaineA.equals(chaineB) " + (chaineA.equals(chaineB)));
System.out.println("String : chaineA == chaineC " + (chaineA == chaineC));
System.out.println("String : chaineA.equals(chaineC) " + (chaineA.equals(chaineC)));
System.out.println("String : chaineC == chaineD " + (chaineC == chaineD));
System.out.println("String : chaineC.equals(chaineD) " + (chaineC.equals(chaineD)));
Dans l'exemple ci-dessus, chaineA et chaineB font référence à la même entrée dans le pool de chaînes, donc == et equals retournent true. Pour chaineC et chaineD, == retourne false car ce sont des instances distinctes, mais equals retourne true car la classe String a redéfini equals pour comparer le contenu des chaînes.
En interne, String.equals vérifie d'abord si les références sont identiques, puis compare les caractères un par un. Cette redéfintiion est cruciale car, pour les chaînes, l'égalité de contenu est plus pertinente que l'égalité de référence.
De même, d'autres classes comme Date redéfinissent equals pour comparer les timestamps. Lorsque vous développez, vous pouvez redéfinir equals dans vos propres classes, par exemple pour comparer des objets Person par leur identifiant unique.