Initialisation des objets Java: maîtrisez votre JLS

Ce post est largement inspiré d’un billet sur le blog de Daniel Schneller.
http://www.danielschneller.com/2010/07/java-object-initialization-order-know.html
*

On considère une classe Chien qui étend la classe Animal.

public class Chien extends Animal { String couleur = null; public Chien() { super(); System.out.println("nom :"+nom); System.out.println("couleur :"+couleur); } public static void main(String[] args) { new Chien(); } }

public class Animal { String nom; public Animal() { if (this instanceof Chien) { ((Chien) this).couleur = "brun"; } nom = "fido"; } }

A votre avis quelle est la sortie produite par ce code?
Le résultat est le suivant.

nom :fido
couleur :null

changeons un peu la classe Chien

public class Chien extends Animal { String couleur; public Chien() { super(); System.out.println("nom :"+nom); System.out.println("couleur :"+couleur); } public static void main(String[] args) { new Chien(); } }

lançons le code

nom :fido
couleur :brun

Vous ne voyez pas la différence ? Regardez bien : on a omis l’initialisation à null de la variable couleur. Ok, super, mais qu’est-ce que ça peut bien changer ? la valeur par défaut d’une String n’est-elle pas la valeur nulle ? Comment ce changement anodin peut modifier le comportement du programme?

Voilà ce qui se passe :

  1. le main appelle le constructeur de Chien
  2. Une instance de Chien est préparée et ses membres initialisés avec les valeurs par défaut (null pour une String, false pour un boolean, 0 pour un int…). A ce moment les affectations “inline” des variables n’ont PAS encore eu lieu.
  3. Le super-constructeur est appelé (le constructeur de la classe Animal) celui-ci affecte une valeur aux attributs “nom” et “couleur”. nom et couleurs ne sont donc plus nuls
  4. C’est ici que cela devient intéressant. - Quand il n’y a pas d’affectation explicite couleur = null; le constructeur de la classe Chien reprend son exécution en affichant “couleur :brun”
  • Quand il y a une affectation explicite, celle-ci est alors exécutée avant que le reste du constructeur ne soit exécuté. ce qui affiche “couleur :null”. ce comportement est décrit dans la section 12.5 de la JLS on peut y lire (au point 4) que les initialiseurs de variables sont exécutés juste APRES le super-constructeur.

Ce code est plutôt mauvais : on initialise l’objet Chien dans le constructeur de Animal en utilisant un instanceof pas très propre. Animal étant la classe mère il ne devrait pas avoir connaissance d’une classe fille comme Chien. Même si ce code est plutôt improbable “dans la vraie vie”, Il permet de mieux comprendre la création d’instances de classes en Java.