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 :

Generics et polymorphisme : comprends pas


Sujet :

Langage Java

  1. #1
    Membre éclairé

    Homme Profil pro
    Inscrit en
    Juillet 2006
    Messages
    766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 766
    Par défaut Generics et polymorphisme : comprends pas
    Edit : l'ensemble du post est un peu confus (j'étais vénère ). La version anglaise sur le fourm Sun est plus claire : http://forum.java.sun.com/thread.jspa?threadID=5262288

    Je crée des listes de Couples<Integer, String>.
    Quand j'enlève un de ces couples, j'ai une liste Enfant qui doit enlever le String correspondant grace à ces fonction :

    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
     
     
    class MyList<String> extends Vector<String> implements ChildList{
     
        public void fireClear() {
            clear();
        }
     
        /**
         * ici o correspond à un Couple
         * @param o
         */
        public void fireRemove(Couple<Integer, String> couple) {
            System.out.println("avant :"+this);
            remove(couple.getRightElement());
            System.out.println("après :"+this);
        }
       /* Si on veut enlever directement le String ou n'importe quoi */
        public void fireRemove(Object o) {
            remove(o);
        }
     
    }
    Puis je remplis mes listes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    ParentCoupleList<Integer, String> listParent=new ParentCoupleList<Integer, String>();
    Couple<Integer, String>c1,c2,c3,c4,c5;
    c1=new Couple<Integer, String>(1, "1");
    c2=new Couple<Integer, String>(2, mySuperString);
    listParent.add(c1);listParent.add(c2);
     
    myList=new MyList();
    myList.add(mySuperString);myList.add(myOtherSuperString);
     
    listParent.registerChildList(myList);
    Et en principe, quand je supprime le couple c2 de la listeParent, je lance la fonction fireRemove(c2).

    Malheureusement, le debugguer me dit que c'est la fonction fireRemove(Object o) plutot que fireRemove(Couple<Integer, String> couple) qui est choisie.

    Pourquoi donc ??????????????????????????????????

    PS : la classe ParentCoupleList a été testée et fonctionne correctement

  2. #2
    Membre éclairé

    Homme Profil pro
    Inscrit en
    Juillet 2006
    Messages
    766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 766
    Par défaut Problème tout bête de surcharge de méthode avec héritage
    J'ai un problème tout bête dans une classe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     
     public void fireRemove(Couple couple) {
            remove(couple.getRightElement());
        }
     
        public void fireRemove(Object o) {
            if (o instanceof Couple) fireRemoveCouple((Couple)o);
            else remove(o);
        }
    QUand je lance la fonction fireRemove(unCouple), comme Couple extends Object, cet ##{{ de JVM lance la fonction public void fireRemove(Object o), au lieu de celle destinée au Couple.

    Je suppose que la JVM a ses raisons et mon bouquin de certification ne m'en dit pas davantage.
    Je contourne donc le problème ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     public void fireRemoveCouple(Couple couple) {
            remove(couple.getRightElement());
        }
     
        public void fireRemove(Object o) {
            if (o instanceof Couple) fireRemoveCouple((Couple)o);
            else remove(o);
        }
    Mais c'est pas beau, et si les héritages se multiplient, ce sera pire. Une idée ?

  3. #3
    Membre expérimenté
    Inscrit en
    Juin 2003
    Messages
    292
    Détails du profil
    Informations forums :
    Inscription : Juin 2003
    Messages : 292
    Par défaut
    Moi aussi j ai revu mon bouquin de certif... et ca ne dit rien...
    c est pas logique ce qui ce passe... je te conseil de poster ton problem sur javaranch.com ou directement sur le site de sun.
    Tu toucheras une beaucoup plus large audience... si tu as besoin d aide pour formuler ta question en anglais envoie moi MP.

    Fais nous partager ta reponse plus tard.

  4. #4
    Membre éclairé

    Homme Profil pro
    Inscrit en
    Juillet 2006
    Messages
    766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 766
    Par défaut
    Ce qui est bizarre, c'est qu'avec :

    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 void enleve(Object objet) {
     
            assert objet != null : "Erreur objet null";
            assert !(objet instanceof Eleve);
            assert !(objet instanceof Professeur);
     
            //On ne fait rien
            if (objet instanceof MembreAdministration) {
                return;
            }
        }
     
        public void enleve(Eleve eleve) {
            assert eleve != null : "Erreur objet null";        
             this.facade.enleveListeEleves(v);       
        }
     
        public void enleve(Professeur prof) {
            assert prof != null : "Erreur objet null";
             this.enleveProfPrincipal();
     
        }
    ca marche nickel. Donc je me demande si il n'y a pas une méga embrouille avec les générics. Mais même en enlevant uen bonne partie de tout ce qui touche à ces générics, je passe toujours par la fonction fireRemove(Object o) et pas fireRemove (Couple c)

    Merci aux admin d'avoir recoupé mes messages - je me suis bien embourbé dans ma mouise . Je vais m'coucher !

  5. #5
    Membre éclairé

    Homme Profil pro
    Inscrit en
    Juillet 2006
    Messages
    766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 766
    Par défaut
    Plus bizarre encore :
    Quand je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
     public void fireRemove(Couple<Integer, String> couple) {
            System.out.println("avant :"+this);
            remove(couple.getRightElement());
            System.out.println("après :"+this);
        }
     
        public void fireRemove(Object o) {
            if (o instanceof Couple) fireRemove((Couple)o);
            remove(o);
        }
    Ca marche nickel alors que ca pourrait boucler à l'infini. La conversion en Couple pousse vers public void fireRemove(Couple<Integer, String> couple), ce qui me fait dire que les generics n'ont rien à voir là-dedans.

    Par contre si à l'extérieur de la Class je fais :
    registeredChildLists.get(i).fireRemove((Couple)couple);

    Alors je passe par public void fireRemove(Object o)

    Comme ca n'est pas documenté, je me dis finalement que ca marche au petit bonheur la chance - on ne peut pas leur en vouloir, mais c'est très contre-intuitif et il faut le savoir.

    Ou alors j'ai fait une méga bévue de débutant . Je vais tenter la traduction pour demain.

  6. #6
    Membre Expert
    Avatar de gifffftane
    Profil pro
    Inscrit en
    Février 2007
    Messages
    2 354
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Février 2007
    Messages : 2 354
    Par défaut
    Change de JVM, ou change de debogueur, ou efface tout et recommence.

    Pour résumer, en cas de définition mutliple d'une méthode, l'appel choisi sera celui correspondant aux classes déclarées, non aux classes effectives.

    Par exemple, si tu as
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    void toto(Object trux){ ... } /* 1 */
     
    void toto[String truc){ ... } /* 2 */
    L'appel toto("hello world") choisira 2.

    Par contre, Object hello = "hello world" ; toto(hello); choisira 1.

  7. #7
    Membre éclairé

    Homme Profil pro
    Inscrit en
    Juillet 2006
    Messages
    766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 766
    Par défaut
    Négatif - j'ai déclaré mes objets en Couple. Que ce soit Couple<Integer, String > monCouple ou Couple monCouple, sans generics, cela ne change rien.
    C'est bien sûr la JVM standard de Sun pou M$.


    Dans l'exemple montré, j'utilise un fonction appelée fireRemove(Couple c) et fireRemove (Object o).

    Ces fonctins sont lancées par une autre classe contenant les fonctions remove(Couple<Integer, String>) et remove (Object o). Et dans ce cas, ca se passe bien, avec ou sans generics.

    Je vais tout caser et tout refaire - et on verra si j'ai une réponse sur les sites anglais.

  8. #8
    Membre éclairé

    Homme Profil pro
    Inscrit en
    Juillet 2006
    Messages
    766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 766
    Par défaut
    La nuit portant sommeil et donc calme, j'ai fait un post en Anglais qui ressemble à quelque chose et réunit de façon claire l'ensemble du problème :
    http://forum.java.sun.com/thread.jspa?threadID=5262288

  9. #9
    Membre expérimenté
    Inscrit en
    Juin 2003
    Messages
    292
    Détails du profil
    Informations forums :
    Inscription : Juin 2003
    Messages : 292
    Par défaut
    Citation Envoyé par nicorama Voir le message
    La nuit portant sommeil et donc calme, j'ai fait un post en Anglais qui ressemble à quelque chose et réunit de façon claire l'ensemble du problème :
    http://forum.java.sun.com/thread.jspa?threadID=5262288
    Alors c est resolu ou pas? j ai pas bien compris ton dernier post sur http://forum.java.sun.com/thread.jspa?threadID=5262288

  10. #10
    Membre éclairé

    Homme Profil pro
    Inscrit en
    Juillet 2006
    Messages
    766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 766
    Par défaut
    Je pense que j'ai trouvé le truc. Accrochez-vous !
    Lorsque je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
     /**
         */
        public void fireRemove(Couple<Integer, String> couple) {
            remove(couple.getRightElement());
        }
     
        public void fireRemove(Object o) {
            if (o instanceof Couple) fireRemove((Couple)o);
            remove(o);
        }
    ca passe par fireRemove(Object o) puis fireRemove(Couple<Integer, String> couple);
    Si j'enlève juste la ligne avec instance, ca boucle à l'infini. Or ceci est parfaitement reproduisible :


    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
     
    public class TestLists {
     
        public void printString(String s){    
            System.out.println("j'ai une string");
        }
     
        public void printString(Object o){
            System.out.println("J'ai un objet");
            printString(o);
        }    
     
        public static void main(String[] args) {
            // TODO code application logic here
            TestLists t=new TestLists();
            ArrayList l=new ArrayList();
            l.add("yeaaaarh");        l.add("what ?!?");
            t.printString(l.get(0));        
        }
     
    }
    Ce code va boucler à l'infini sauf si on déclare : ArrayList<String> l=new ArrayList(); Dans ce cas, on passe direct à la "bonne" fonction.Ce que je ne comprenais pas c'est pourquoi l'appel de registeredChildLists.get(i).fireRemove(o); ou meme registeredChildLists.get(i).fireRemove((Couple)o); appelait la mauvaise fonction.

    J'ai réussit à reproduire un phénomène différent mais semblable :
    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
    25
    26
    27
    28
    29
    30
     
    public class TestLists {
     
     
        public void printString(String s){    
            System.out.println("j'ai une string");
        }
     
        public void printString(Object o){
            System.out.println("J'ai un objet");
            printString(o);
        }
     
        public void intermittent(ArrayList l){
            printString(l.get(0));
     
        }
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            // TODO code application logic here
            TestLists t=new TestLists();
            ArrayList<String>  l=new ArrayList();
            l.add("year");
            l.add("what");
            t.intermittent(l);
     
        }
    }
    Ca boucle à l'infini.
    Bien que j'ai déclaré un ArrayList<String> l=new ArrayList(); la fonction intermittent s'en fiche (enfoiré d'intermittent !)


    Reprenons mon gros code initial : J'ai une Classe ParentList associé à un tableau de ChildList. Parmi ces ChildList, il y en a un de classe MyList.
    MyList implements l'interface ChildList, donc la fonction fireRemove(Object o);

    Au moment de la compilation de ParentList, bien que je signale qu'il faille éxécuter la fonction fireRemove() avec un Couple, le compilateur sait que j'ai un ChildList, mais pas un MyList. Le compilateur connait donc la fonction fireRemove(Object o) mais pas fireRemove(Couple c). Le compilateur doit donc poser un marqueur sur la mauvaise fonction.

    De même en compilant la fonction intermittent, il met un marqueur sur la mauvaise fonction bien que j'ai signaler que mes objets sont des String a la déclaration !

    Désolé, je peux pas faire plus simple comme explication. La parade est de vérifier que votre IDE connait la fonction à executer. Avec NotePad, ca devient tendu tendu .

  11. #11
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Euh... Dans le code que tu donnes le problème ne vient pas du compilateur mais bien de ton code.

    Dans cette méthode :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        public void intermittent(ArrayList l){
            printString(l.get(0)); // => printString(Object)
        }
    Comme le paramètre ArrayList n'est pas typé, il considère que c'est une liste d'objet, donc l.get(0) te renvoi un Object, donc le compilateur génèrera un code qui appellera printString(Object).

    Si tu types cette méthode tu n'a plus ce problème !


    D'ailleurs ce code compile avec 2 warnings, ce qui t'aurait mis sur la piste du problème si tu les avais corrigé

    a++

    PS : Au passage : il vaut mieux utiliser l'interface List que ArrayList pour les paramètres de méthodes, afin de conserver une meilleure abstraction et ne pas imposer d'implémentation inutilement...

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

Discussions similaires

  1. Erreur Objet requis : 'this' --> Comprend pas!!
    Par Grozeil dans le forum ASP
    Réponses: 3
    Dernier message: 30/03/2005, 10h46
  2. [thread][methodologie]Quelque chose que je ne comprends pas!
    Par norkius dans le forum Général Java
    Réponses: 5
    Dernier message: 16/03/2005, 15h01
  3. sql ne comprend pas mon where!et me demande des parametres
    Par marie10 dans le forum Langage SQL
    Réponses: 10
    Dernier message: 20/04/2004, 12h08
  4. [Rave] un message que je ne comprends pas
    Par Clotilde dans le forum Rave
    Réponses: 2
    Dernier message: 30/09/2003, 22h46

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