IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

Petit test pour des pro du java


Sujet :

Langage Java

  1. #1
    Membre actif Avatar de vincent63
    Inscrit en
    Octobre 2005
    Messages
    198
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 198
    Points : 205
    Points
    205
    Par défaut Petit test pour des pro du java
    Bonjour,
    Dans une application, je me suis retrouvé confronté à une null pointer exception. Ce genre de problème est en général simple à résoudre. Là, la correction a été un peu plus subtile. Du coup je vous propose de la chercher. J'espère que ça vous amusera un peu

    La règle : ne pas utiliser le debugger => trop facile
    Eviter les corrections du genre si truc == null alors truc = new Machin();
    La correction ne demande en fait qu'une très très légère modification.

    Voilà une version simplifiée des classes qui vont vous permettre de reproduire le bug.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    package com.test.java;
     
    public class Application {
     
        public static void main(String[] args) {
            new Fille().printMessage();
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package com.test.java;
     
    public class Fille extends Mere {
     
        private String message = null;
     
        public Fille() {
            super();
        }
     
        public void initialiseFille() {
            System.err.println("1. J'initialise l'object message");
            message = "Bonjour le monde";
            System.err.println("2. Sa valeur est : " + message);
        }
     
        public void printMessage() {
            System.err.println("3. J'affiche la taille du message");
            System.err.println("Taille du message = " + message.length());
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package com.test.java;
     
    public abstract class Mere {
     
        public Mere() {
            initialiseMere();
        }
     
        private void initialiseMere() {
            initialiseFille();
        }
     
        public abstract void initialiseFille();
    }
    "Ils ne savaient pas que c'était impossible... alors ils l'ont fait." Mark Twain

  2. #2
    Membre confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Août 2007
    Messages
    509
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Août 2007
    Messages : 509
    Points : 622
    Points
    622
    Par défaut
    Citation Envoyé par vincent63 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    package com.test.java;
     
    public class Application {
     
        public static void main(String[] args) {
            new Fille().printMessage();
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package com.test.java;
     
    public class Fille extends Mere {
     
        private String message = null;
     
        public void initialiseFille() {
            System.err.println("1. J'initialise l'object message");
            message = "Bonjour le monde";
            System.err.println("2. Sa valeur est : " + message);
        }
     
        public void printMessage() {
            System.err.println("3. J'affiche la taille du message");
            System.err.println("Taille du message = " + message.length());
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package com.test.java;
     
    public abstract class Mere {
     
        public Mere() {
            initialiseMere();
        }
     
        private void initialiseMere() {
            initialiseFille();
        }
     
        public abstract void initialiseFille();
    }
    Le problème se trouve dans le main quand tu appelles la methode printMessage(). La
    variable message n'est pas initialisée.

  3. #3
    Membre actif Avatar de vincent63
    Inscrit en
    Octobre 2005
    Messages
    198
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 198
    Points : 205
    Points
    205
    Par défaut
    Effectivement, la variable message est null.
    On peut le voir aux traces lors de l'exécution.
    Mais si tu regardes tes traces, tu peux aussi voir que juste avant de demander sa taille, on affiche sa valeur et elle n'est pas null.
    On obtient quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    1. J'initialise l'object message
    2. Sa valeur est : Bonjour le monde
    3. J'affiche la taille du message
    NullPointerException...
    Il te reste donc à trouver la correction.
    Bon courage.
    "Ils ne savaient pas que c'était impossible... alors ils l'ont fait." Mark Twain

  4. #4
    Modérateur
    Avatar de Alkhan
    Homme Profil pro
    ingénieur full stack
    Inscrit en
    Octobre 2006
    Messages
    1 232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur full stack

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 232
    Points : 2 061
    Points
    2 061
    Par défaut
    bonjour,
    la c'est un peu facile
    il suffit que ta variable message soit declaré comme ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    private String message = "";
    Il n'y a pas de problème, il n'y a que des solutions.
    Cependant, comme le disaient les shadoks, s'il n'y a pas de solution, c'est qu'il n'y a pas de problème.
    Si toutefois le problème persiste, la seule solution restante est de changer le périphérique qui se trouve entre la chaise et l'écran

    Mes Articles : Mon premier article est sur le language D
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Rédacteur
    Avatar de eclesia
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    2 108
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 108
    Points : 3 203
    Points
    3 203
    Par défaut
    trouvé.

    le constructeur de la classe mère donne bien une valeur au message mais le constructeur de la classe fille la repasse a null.

    il faut appeller le initialiseFille apres le super, ou mettre la variable message dans la classe mère ( en passant le private en protected).
    Systèmes d'Informations Géographiques
    - Projets : Unlicense.science - Apache.SIS

    Pour un monde sans BigBrother IxQuick ni censure RSF et Les moutons

  6. #6
    Membre du Club
    Profil pro
    Architecte logiciel
    Inscrit en
    Janvier 2006
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Architecte logiciel
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2006
    Messages : 28
    Points : 48
    Points
    48
    Par défaut
    il ne faut pas initialiser les valeures par defaut,car ca les réinitialises apres l'appel du constructeur parent. Donc faire une déclaration comme suis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    private String message;
    en plus la fonction inialiserfille semble servir a initaliser les valeures de la fille... c'est contradictoire avec la déclaration.

  7. #7
    Membre averti
    Inscrit en
    Octobre 2007
    Messages
    311
    Détails du profil
    Informations forums :
    Inscription : Octobre 2007
    Messages : 311
    Points : 318
    Points
    318
    Par défaut
    Citation Envoyé par eclesia Voir le message
    trouvé.

    le constructeur de la classe mère donne bien une valeur au message mais le constructeur de la classe fille la repasse a null.

    il faut appeller le initialiseFille apres le super, ou mettre la variable message dans la classe mère.

  8. #8
    Membre actif Avatar de vincent63
    Inscrit en
    Octobre 2005
    Messages
    198
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 198
    Points : 205
    Points
    205
    Par défaut
    Félicitations pour toutes ces réponses. Celle que j'attendai a été donné par fallo.
    En effet, le petit truc subtil qui fait planter ce petit bout de code est le "=null" dans la déclaration.
    En l'enlevant, tout fonctionne sans avoir à déplacer ni méthode ni attribut de classe.
    Pour fallo
    "Ils ne savaient pas que c'était impossible... alors ils l'ont fait." Mark Twain

  9. #9
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    Je ne suis pas tout à fait d'accord sur la réponse : cela résoud bien le "bug" mais ce n'est pas très propre !!!


    En fait ce n'est pas un bug en soit puisque c'est un effet de l'ordre de création des objets, qui suit le déroulement suivant :

    1. Allocation de l'espace mémoire pour l'objet. Tous les attributs sont initialisés à leur valeur par défaut (null pour les références, 0/0.0/false pour les types primitifs).
    2. Les constructeurs sont appellés de manière récursive jusqu'au constructeur de base. Les constructeur s'exécute donc en ordre inverse (du plus haut au plus bas de la hierarchie), sachant que chaque constructeur s'effectue en deux étapes :
      • Exécution d'un méthode <init> qui exécutes le "code d'instance" (initialisation des attributs et bloc {} de la classe).
      • Exécution du code du constructeur.

    Pour plus de détail jetez un oeil aux specs : http://java.sun.com/docs/books/jls/t...tion.html#12.5

    Ce qui donne dans ton cas :
    • Allocation de la mémoire pour un objet Fille
    • Initialisation et exécution du constructeur de Object (qui ne fait rien).
    • Initialisation de Mere (ce qui ne fait rien), et exécution du constructeur (qui appelle initialiseMere() puis initialiseFille()).
    • Initialisation de Fille (qui exécute message = null;) et exécution du constructeur (qui ne fait rien).


    Du coup message se retrouve à nouveau à null...





    Là où je ne suis pas d'accord sur la solution, c'est que le problème vient plutôt du fait que le constructeur de la classe Mere appelle (indirectement) une de ses méthodes virtuelles (initialiseFille() en l'occurence)...

    Cela devrait être interdit car cela peut générer un grand nombre de problème de ce genre, et cela implique que les classes filles respectent un certains nombres de conditions liés à l'implémentation de la classe parente...


    a++

  10. #10
    Membre actif Avatar de vincent63
    Inscrit en
    Octobre 2005
    Messages
    198
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 198
    Points : 205
    Points
    205
    Par défaut
    Là où je ne suis pas d'accord sur la solution, c'est que le problème vient plutôt du fait que le constructeur de la classe Mere appelle (indirectement) une de ses méthodes virtuelles (initialiseFille() en l'occurence)...
    Je suis assez d'accord avec toi. En fait, il me semble que cela fait parti des préconisations que l'on peut trouver dans le livre Java efficace, à savoir qu'un constructeur ne devrait appeller que des méthodes 'private final'. Cela évite les problèmes de ce genre.

    Ceci dit, je trouvai amusant de voir qu'en utilisant ce type d'architecture (ie une sorte de patron de méthode sur un constructeur), on pouvait rencontrer ce genre d'erreur peut-être pas évidente à corriger.

    Car après tout, cette façon d'initialiser un objet pourrait tout à fait être sensée.

    Dans le cas qui m'intéresse, il s'agissait d'initialiser un composant graphique. La partie supérieure est identique à tous les objets filles. La spécialisation se fait justement dans la partie inférieur du composant. D'où l'initialisationFille qui permettait aux filles de créer leur propre partie.

    Il y a surement de meilleurs façons de faire, mais dans la hâte c'est celle là que j'avais choisi.

    Cela m'a, en tout cas, permis de voir la différence entre la déclaration simple d'un object et sa déclaration + initialisation à null qui de toute évidence ne sont pas traités de la même manière.

    La solution proposée permettait juste de mettre en évidence cette différence.

    En tout cas, je te remercie pour tes précisions et pour le lien qui me semble assez intéressant.
    "Ils ne savaient pas que c'était impossible... alors ils l'ont fait." Mark Twain

  11. #11
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par vincent63 Voir le message
    Je suis assez d'accord avec toi. En fait, il me semble que cela fait parti des préconisations que l'on peut trouver dans le livre Java efficace, à savoir qu'un constructeur ne devrait appeller que des méthodes 'private final'. Cela évite les problèmes de ce genre.
    private ou final. Du moment que la méthode est private ou final elle ne peut pas être redéfini dans une éventuelle classe fille, ce qui évite ce genre de problème


    Citation Envoyé par vincent63 Voir le message
    Car après tout, cette façon d'initialiser un objet pourrait tout à fait être sensée.
    L'initialisation, c'est le rôle du constructeur. Chaque constructeur doit initialiser les éléments de son propre type sans avoir à se soucier des éventuels types enfants...

    De plus cela simplifie le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public abstract class Mere {
     
        public Mere() {
            // initialisation ici
        }
     
    }
     
     
    public class Fille extends Mere {
     
        private String message = null;
     
        public Fille() {
            System.err.println("1. J'initialise l'object message");
            message = "Bonjour le monde";
            System.err.println("2. Sa valeur est : " + message);
        }
     
        public void printMessage() {
            System.err.println("3. J'affiche la taille du message");
            System.err.println("Taille du message = " + message.length());
        }
    }
    Et c'est plus propre car il n'y a pas de méthode initialiseFille() en public (qui pourrait donc être rappelé par la suite )

    a++

  12. #12
    Membre actif Avatar de vincent63
    Inscrit en
    Octobre 2005
    Messages
    198
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 198
    Points : 205
    Points
    205
    Par défaut
    private ou final tu as raison , on va dire que j'ai oublié le ou

    L'exemple que j'ai donné était une version simplifiée. L'objectif était juste de montrer cette subtilité dans la déclaration, pas de montrer un cas concret ou réel d'utilisation de ce genre d'archi.

    L'idée, dans mon appli, était en gros d'initialiser dans la mère un composant principale, mettons un JPanel, avec deux parties.

    La première qui contient une partie commune à tous les objects qui héritent de la classe mère.

    La seconde qui est spécifique à chaque fille.

    L'idée était donc à l'initialisation de la mère d'ajouter le composant spécifique sous le composant commun défini dans la classe mère, d'où l'utilisation d'une méthode abstraite qui devait renvoyer le composant spécifique. C'est vraiment l'idée du patron de méthode réutilisé dans la construction d'un object.

    Bon, sûr que dit comme ça, ça ne doit pas être très clair. Mais il ne faut pas s'arrêter sur l'exemple qui est vraiment une version simplifié. Parce que là évidement, cela n'a aucun intéret, je te l'accorde.

    L'initialisation, c'est le rôle du constructeur. Chaque constructeur doit initialiser les éléments de son propre type sans avoir à se soucier des éventuels types enfants...
    Là dessus je ne suis pas tout à fait d'accord. Il n'est pas impensable de demander aux classes filles des "précisions" sur leur spécialisation qui permettraient de modifier certains comportements. C'est exactement ce qui se fait sur un patron de méthode. Une méthode principale qui délègue aux filles une partie du travail pour exploiter leurs particularités. C'est tout à fait envisageable dans une construction.
    "Ils ne savaient pas que c'était impossible... alors ils l'ont fait." Mark Twain

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. quelque petite question pour des windows messages
    Par julspower dans le forum C++
    Réponses: 3
    Dernier message: 02/12/2008, 17h54
  2. Test pour des modèles non-ActiveRecord
    Par Flackou dans le forum Ruby on Rails
    Réponses: 1
    Dernier message: 11/08/2008, 10h23
  3. pour des pros
    Par m3am3a dans le forum C
    Réponses: 3
    Dernier message: 24/11/2007, 21h37
  4. Un défi pour des pros
    Par Total_amateur dans le forum Langage
    Réponses: 9
    Dernier message: 17/10/2006, 10h03
  5. [Lambda] un petit test pour comprendre
    Par airod dans le forum Tkinter
    Réponses: 4
    Dernier message: 01/03/2006, 14h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo