La classe Object en Java
Méthodes héritées par tout objet Java depuis java.lang.Object : toString, equals, hashCode, getClass, clone et finalize.
Toute classe en Java — que vous écriviez extends Object ou non — se trouve sous java.lang.Object dans la hiérarchie des types. Cela signifie que chaque référence que vous détenez dispose d'un petit ensemble de méthodes : toString, equals, hashCode, getClass, et quelques autres. Comprendre ce qu'elles font par défaut, et quand vous devriez les redéfinir, fait la différence entre des objets qui fonctionnent bien avec les collections, les débogueurs et les frameworks — et ceux qui ne le font pas.
Ce chapitre dresse la carte du territoire. Les prochains chapitres examinent en détail les méthodes spécifiques (equals/hashCode, toString, clone) une par une.
Extension implicite
Écrivez une classe sans clause extends :
public class Box {
int contents;
}Le compilateur la traite comme si vous aviez écrit public class Box extends Object. C'est pourquoi vous pouvez passer un Box à tout ce qui est déclaré comme Object — chaque type référence est en définitive un Object.
Les méthodes héritées en un coup d'œil
| Méthode | Ce que la version par défaut fait |
|---|---|
toString() | Retourne ClassName@hashCodeHex — presque jamais ce que vous voulez |
equals(Object) | Égalité de référence (==) |
hashCode() | Une valeur dérivée de l'identité de l'objet, pas de son contenu |
getClass() | Le jeton Class<?> d'exécution — jamais null |
clone() | Une copie superficielle champ par champ, mais uniquement sur les classes qui implémentent Cloneable ; sinon lève une exception |
wait(), notify(), notifyAll() | Primitives de moniteur bas niveau utilisées avec synchronized |
finalize() | Crochet appelé par le GC avant de récupérer un objet — déprécié, ne pas utiliser |
Les trois premières — toString, equals et hashCode — sont celles que presque toute classe portant des valeurs devrait redéfinir, car les versions héritées décrivent l'identité d'un objet plutôt que son contenu. getClass s'appelle sur les objets mais ne se redéfinit jamais. Les primitives de threading sont rarement utilisées directement. clone et finalize sont à éviter dans le code moderne (clone fait l'objet d'un chapitre dédié ; finalize est remplacé par try-with-resources et Cleaner).
record (Java 16+), le compilateur génère toString, equals et hashCode pour vous à partir des composants — tous les trois basés sur le contenu, pas sur l'identité. Cela supprime la majeure partie du code répétitif dont ce chapitre traite. Voir Java Records.toString — la valeur par défaut n'est pas utile
Le toString hérité retourne quelque chose comme Box@1540e19d. C'est le nom de la classe et le code de hachage d'identité en hexadécimal — inutile pour la journalisation, le débogage ou tout type de diagnostic :
Box b = new Box();
System.out.println(b); // Box@1540e19dRedéfinissez-le pour retourner quelque chose de lisible — println, la concaténation de chaînes, les frameworks de journalisation et les débogueurs d'IDE appellent tous toString pour vous, donc une bonne implémentation est bénéfique partout :
@Override
public String toString() {
return "Box[contents=" + contents + "]";
}Le chapitre suivant explique comment bien le faire.
equals et hashCode — ils vont ensemble
Le equals hérité ne retourne true que lorsque les deux références pointent vers le même objet :
String a = new String("hi");
String b = new String("hi");
System.out.println(a == b); // false — different objects
System.out.println(a.equals(b)); // true — String overrides equalsString redéfinit equals pour comparer le contenu. Une classe que vous écrivez ne le fait pas, à moins que vous ne le redéfinissiez vous-même. Et dès que vous redéfinissez equals, vous devez aussi redéfinir hashCode — sinon vos objets se comporteront silencieusement de façon incorrecte dans HashSet et HashMap. Le chapitre sur equals et hashCode couvre les règles exactes.
equals sans redéfinir hashCode et deux objets que vous considérez égaux peuvent se retrouver dans des buckets de hachage différents — un HashSet les stocke tous les deux sans problème, et map.get(key) retourne null pour une clé qui est clairement présente. Redéfinissez toujours les deux ensemble, et maintenez-les cohérents : des objets égaux doivent retourner des codes de hachage égaux.getClass — le jeton de type à l'exécution
getClass() retourne l'objet Class<?> décrivant le type d'exécution :
Object o = "hello";
System.out.println(o.getClass().getName()); // java.lang.StringIl est utilisé dans le code réflexif, par les implémentations d'equals qui veulent des comparaisons de type exact, et par les sorties de débogage. Notez que getClass() est final — vous ne pouvez pas le redéfinir.
clone et Cloneable
Object.clone() est protected et ne réussit que sur les classes qui déclarent explicitement implements Cloneable. Le résultat est une copie superficielle : une nouvelle instance avec les mêmes valeurs de champ, y compris les mêmes références aux sous-objets mutables. C'est une API notoirement maladroite, couverte en détail dans le chapitre sur le clonage.
wait / notify
Ces méthodes, ainsi que notifyAll, font partie des primitives de concurrence bas niveau d'origine de Java. Elles sont liées aux blocs synchronized et utilisées pour construire des modèles d'attente de condition. Dans le code moderne, préférez les utilitaires de plus haut niveau dans java.util.concurrent (verrous, BlockingQueue, CompletableFuture) ; wait/notify brut est rare en dehors des internes de bibliothèque.
finalize — laissez-le tranquille
finalize() était autrefois la façon dont le GC donnait à votre objet une dernière chance de libérer des ressources. Il est déprécié depuis Java 9 et supprimé dans les versions plus récentes. Utilisez try-with-resources pour les E/S et java.lang.ref.Cleaner pour le cas très rare où vous devez exécuter du code après la collecte.
Un exemple concret
La suite
La redéfinition la plus courante — et la plus sujette aux erreurs — d'une méthode Object est equals associée à hashCode. Le chapitre suivant présente le contrat que les deux méthodes doivent respecter et les patterns pour le faire correctement. Continuer vers Java equals et hashCode.