instanceof en Java : faut-il vérifier la valeur null ? Plongeons sous le capot de la JVM
\n\nChaque développeur Java se retrouve tôt ou tard face à un dilemme : faut-il écrire avant l'appel à instanceof la lourde construction if (obj != null && obj instanceof SomeClass) ou peut-on se contenter d'un simple instanceof ? Cette question, qui a recueilli des milliers de vues sur Stack Overflow, reste d'actualité. Penchons-nous une fois pour toutes sur le fonctionnement de cet opérateur « sous le capot » et déterminons si la double vérification relève de la paranoïa ou d'une bonne pratique.
Si vous programmez en Java et souhaitez écrire un code propre, sûr et efficace, cet article est pour vous. Nous ne nous contenterons pas de répondre par « oui » ou « non », mais nous montrerons le bytecode, explorerons la spécification de la JVM et présenterons des exemples concrets.
\n\nRéponse courte : votre intuition est correcte
\n\nAllons droit au but : la vérification de null avant instanceof n'est pas nécessaire. L'opérateur instanceof en Java est conçu de telle sorte que si l'opérande gauche est null, il retourne toujours false. Aucun NullPointerException ne sera levé. Cela est spécifié dans la spécification du langage Java (§15.20.2) et confirmé par le comportement de toutes les implémentations existantes de la JVM.
Mais ne nous arrêtons pas à cette simple affirmation. Pourquoi cela a-t-il été fait ainsi ? Comment cela fonctionne-t-il au niveau des instructions machine ? Et quand la double vérification peut-elle être justifiée ?
\n\nComment instanceof fonctionne sous le capot : un regard sur le bytecode
\n\nConsidérons une classe et une méthode simples :
\n\npublic class InstanceofTest {\n public static boolean check(Object obj) {\n return obj instanceof String;\n }\n}\n\nCompilons et examinons le bytecode (commande javap -c InstanceofTest) :
public static boolean check(java.lang.Object);\n Code:\n 0: aload_0\n 1: instanceof #7 // class java/lang/String\n 4: ireturn\n\nNous voyons seulement trois instructions :
\n- \n
aload_0— charge la référence de l'objet depuis la variable locale 0 (notre paramètreobj) \n instanceof #7— effectue la vérification de type \n ireturn— retourne le résultat (0 ou 1) \n
Remarquez : il n'y a aucune instruction pour vérifier la valeur null ! L'instruction JVM instanceof gère elle-même ce cas. Si la pile d'opérandes contient null (une valeur de référence spéciale pointant vers nulle part), l'instruction retourne simplement 0 (false).
Que se passe-t-il au niveau de la JVM ?
\n\nÀ l'intérieur de la machine virtuelle Java, l'instruction instanceof effectue les étapes suivantes :
- \n
- Vérification de null : Si la référence est
null, retourne immédiatementfalse. Cela est fait au tout début, avant toute opération mémoire. \n - Obtention du pointeur de classe : Si l'objet n'est pas null, la JVM extrait de son en-tête le pointeur vers la classe (dans HotSpot, cela fait partie de la structure
mark wordetklass pointer). \n - Vérification de compatibilité : La JVM vérifie si la classe de l'objet est la même classe, une sous-classe ou une implémentation d'interface que celle spécifiée dans l'opérande droit. Pour cela, un algorithme rapide avec mise en cache des résultats (inline caching) et une recherche dans la chaîne d'héritage sont utilisés. \n
Ainsi, la vérification de null n'est pas une « particularité du langage », mais une propriété fondamentale de l'implémentation de la JVM, rendant le code plus sûr et plus concis.
\n\nExemples de code : vérifions en pratique
\n\nAssurons-nous que cela fonctionne en écrivant un test simple :
\n\npublic class NullInstanceofDemo {\n public static void main(String[] args) {\n String text = "Hello";\n String nullString = null;\n\n System.out.println("text instanceof String: " + (text instanceof String)); // true\