Vous aimez ce que vous lisez sur ce blog ?
Envie d'aller plus loin avec véritable formation d'expertise en Java ?
Venez suivre ma formation Masterclasse Expertise Java !

"Même un développeur experimenté a besoin de continuer à apprendre. Et dans cette formation... j'ai appris beaucoup !" - A.G., Java Champion

Sessions intra-entreprises sur demande : contact[at]mokatech.net.
Inscrivez-vous vite !

Java Quiz #4

Soit une classe Personne suivante :

  1. class Personne
  2. {
  3. private String nom;
  4. private Personne ami;
  5.  
  6. /* ... Constructeur paramétré ... */
  7. /* ... Méthode toString() redéfinie pour renvoyer la propriété "nom" ... */
  8. /* ... Accesseurs ... */
  9. }

Quel est le résultat de l'exécution du code suivant (on lance la classe "Main") ?

  1. class Groupe
  2. {
  3. public static final Personne PAUL = new Personne("Paul", Groupe.JACK);
  4. public static final Personne JACK = new Personne("Jack", Groupe.PAUL);
  5. }
  6.  
  7. public class Main
  8. {
  9. public static void main(String... args)
  10. {
  11. System.out.println(Groupe.PAUL.getAmi());
  12. System.out.println(Groupe.JACK.getAmi());
  13. }
  14. }

Réponse :

null
Paul

Ce résultat est dû au processus d'initialisation des classes et de leurs variables (voir aussi le post sur les "forward references") :

  1. La méthode main() de la classe Main est lancéé.
  2. Sa première instruction référence la classe Groupe. Comme c'est la première fois qu'elle est référencée, celle-ci est donc chargée et initialisée selon le processus habituel :
    1. Les variables statiques PAUL et JACK sont déclarées et prennent la valeur par défaut de leur type, à savoir null puisque ce sont des références.
    2. Ces variables sont ensuite initialisées dans l'ordre de leur déclaration :
      1. PAUL est initialisé avec une nouvelle instance de Personne, créée avec les paramètres "Paul" et une référence vers "Groupe.JACK" (ce n'est pas une forward reference car elle ne vérifie pas la règle #3). A cet instant, JACK possède toujours la valeur null, car il n'a pas encore été initialisé. La propriété "ami" de PAUL vaut donc null.
      2. JACK est initialisé avec une nouvelle instance de Personne, créée avec les paramètres "Jack" et une référence vers "Groupe.PAUL", qui lui est bien initialisé. La propriété "ami" de JACK pointe donc bien vers PAUL.
  3. La classe Groupe étant désormais prête, la classe Main peut maintenant exécuter les "System.out" :
    1. PAUL.getAmi() vaut null et affiche donc "null".
    2. JACK.getAmi() référence PAUL et affiche donc "Paul".


Un second exercice

Je vous propose maintenant un second exercice sur le même principe.
Essayez de le résoudre sans exécuter le code, et proposez vos réponses dans les commentaires. La solution sera donnée dans une semaine !

La classe Personne est la même qu'au premier exercice, et on exécute toujours la classe Main.

  1. class Groupe1
  2. {
  3. public static final Personne PAUL = new Personne("Paul", Groupe2.JACK);
  4. }
  5.  
  6. class Groupe2
  7. {
  8. public static final Personne JACK = new Personne("Jack", Groupe1.PAUL);
  9. }
  10.  
  11. public class Main
  12. {
  13. public static void main(String... args)
  14. {
  15. System.out.println(Groupe1.PAUL.getAmi());
  16. System.out.println(Groupe2.JACK.getAmi());
  17. }
  18. }

Réponse (Bravo à G-die et Pticed !) :

Jack
null

Explication :

  1. La méthode main() de la classe Main est lancéé.
  2. Sa première instruction référence la classe Groupe1. Comme c'est la première fois qu'elle est référencée, celle-ci est donc chargée et initialisée selon le processus habituel :
    1. Déclaration de la référence PAUL, possédant la valeur par défaut de son type : null.
    2. Initialisation de PAUL. La référence à la classe Groupe2 déclenche son chargement, interrompant temporairement l'initialisation de PAUL :
      1. Déclaration de la référence JACK, possédant la valeur par défaut de son type : null.
      2. Initialisation de JACK, utilisant une référence vers PAUL qui n'est pas encore totalement initialisée et vaut donc toujours null. On a donc "JACK.ami = null".
    3. L'initialisation de PAUL reprend ; celui-ci reçoit en paramètre de son constructeur l'instance totalement initialisée de JACK. On a donc "PAUL.ami = JACK".
  3. Le programme affiche PAUL.getAmi() puis JACK.getAmi(), c'est-à-dire "Jack" puis "null".

Commentaires

1. Le lundi 17 mars 2008, 13:16 par G-die

Moi je dirai que ça renvoit :
Jack
null

2. Le jeudi 20 mars 2008, 23:16 par Pticed

Je dirais également:
Jack
null

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.