Partage
  • Partager sur Facebook
  • Partager sur Twitter

Héritage et généricité

Je ne comprend pas le tutoriel

Sujet résolu
    7 juillet 2008 à 13:37:20

    Bonjour tout le monde,

    Je suis en train de suivre non sans mal le tutoriel de Java et je ne comprend vraiment rien à la sous partie traitant de l'héritage et de la généricité : http://www.siteduzero.com/tuto-3-27850 [...] tml#ss_part_4

    Est ce qu'une âme charitable pourrait m'éclairer ?

    Edit :

    Après une longue réflexion, le code suivant :
    ArrayList<Voiture> listVoiture = new ArrayList<Voiture>();
                    ArrayList<VoitureSansPermis> listVoitureSP = new ArrayList<VoitureSansPermis>();
                    
                    listVoiture = listVoitureSP;//Interdit ! ! ! !
    


    Est ce que ce code ne planterais pas uniquement parce que la classe ArrayList ne sais pas que Voiture est le super type de VoitureSP ?
    Car à vrai dire l'explication fournis :
    Je sais que même si vous aviez l'habitude de la covariance des variables, ceci n'existe pas sous cette forme avec la généricité !
    Pourquoi cela ?
    
    Imaginez deux secondes que l'instruction interdite soit permise !
    Dans listVoiture, vous avez le contenu de la liste des voitures sans permis, et rien ne vous empêche d'ajouter une voiture... Là où le problème prend toute son envergure, c'est lorsque vous allez vouloir sortir toutes les voitures sans permis de votre variable listVoiture, eh oui ! Vous y avez rajouté une voiture ! :o
    Lors du balayage de la liste vous aurez, à un moment, une référence de type VoitureSansPermis à qui vous tentez d'affecter une référence de type Voiture. Voilà pourquoi ceci est INTERDIT ! !

    Reste complétement mystérieuse pour moi.
    D'avance merci.
    • Partager sur Facebook
    • Partager sur Twitter
      7 juillet 2008 à 16:27:22

      En fait, il faut savoir qu'à la compilation, il y a création des classes génériques, autrement dit, le compilateur remplace tous les <E> par <Voiture> et génère un code pour chaque type, autrement dit :
      public class ArrayList<Voiture> implements Collection<Voiture> ... {
      
          //Implémentation
      
      }
      

      public class ArrayList<VoitureSansPermis> implements Collection<VoitureSansPermis> ... {
      
          //Implémentation
      
      }
      


      Chaque type est différent, et il n'existe aucun lien d'héritage entre eux. Et le fais d'une telle affectation entrainerait un comportement indésirable, voilà pourquoi on a droit à une belle exception à la compilation ( qui en évite une à l'execution ), mais, Java propose une solution, les jokers. Tu passes à ce moment là par ArrayList<?> ou ArrayList<? extends Voiture> ( je connais pas la hierarchie du tuto ), afin de faire ton affectation.

      ArrayList<Voiture> listVoiture = new ArrayList<Voiture>();
      ArrayList<VoitureSansPermis> listVoitureSP = new ArrayList<VoitureSansPermis>();
      
      ArrayList<? extends Voiture> affectation = listVoitureSP; //Exemple d'affectation, 
      //par contre il n'est plus possible d'utiliser les methodes des objets contenus.
      


      • Partager sur Facebook
      • Partager sur Twitter
        7 juillet 2008 à 16:47:39

        Merci de ta réponse, mais cela ne m'éclaire pas beaucoup (enfin un peu quand même si).
        Le truc, c'est que VoitureSansPermis hérite de Voiture. Et je ne comprend pas la nature indésirable de la chose, car tel que je comprend les choses, une tel chose peut se produire tout à fait dans le cas d'un polymorphisme.
        La solution proposer par l'auteur du tutoriel est complétement abstraite pour moi. Je ne comprend pas une seule ligne.
        import java.util.ArrayList;
        public class Test {
         
                public static void main(String[] args) {
                        
                        ArrayList<? extends Voiture> listVoitureSP = new ArrayList(); 
                        afficher(listVoitureSP);          
                }
                
                /**
                 * Méthode générique !
                 * @param <T>
                 * @param list
                 */
                static <T extends Voiture> void afficher(ArrayList<? extends Voiture> list){
                        for(Voiture v : list)
                                System.out.println(v.toString());
                }
                
        }
        


        Merci pour ton aide en tout cas.
        • Partager sur Facebook
        • Partager sur Twitter
          8 juillet 2008 à 13:01:36

          heuuuuuu ya une erreur alors sur le tuto
          enfin une malfacon on va dire

          static <T extends Voiture> void afficher(ArrayList<? extends Voiture> list){
                          for(Voiture v : list)
                                  System.out.println(v.toString());
                  }
          


          T n'est jamais utilise moi quand je fais un truc du genre ca donne :

          public <T extends Serializable> Message(MessageType t, MessengerAction ac,
          			T arg, String emetteur)
          
          • Partager sur Facebook
          • Partager sur Twitter
            8 juillet 2008 à 16:01:53

            Je suis désolé, mais je ne comprend vraiment rien à ton explication...
            Est ce que quelqu'un pourrait me ré expliquer la généricité et l'héritage depuis le début. J'ai bien compris comment marche la généricité, mais appliqué à l'héritage, ca reste complétement opaque pour moi. Merci.
            • Partager sur Facebook
            • Partager sur Twitter
              9 juillet 2008 à 18:41:49

              desole j'ai oublie

              ben heu comment dire la genericite c'est de programmer sans preciser le type de tes donnees

              l'heritage consiste a etendre les fonctionnalitees d'une classe en reprecisant les fonctionnalitees pour les adapter a tes besoins

              par exemple:

              prend une classe abstraite Banque
              tu pourrais faire heriter une classe
              Lcl, Bnp, ect... de Banque avec chaqunes leurs specificitees

              • Partager sur Facebook
              • Partager sur Twitter
                9 juillet 2008 à 20:09:35

                A vrai dire, j'ai compris ce que tu m'explique juste au dessus. Je doit certainement mal expliquer ce que j'aimerais que l'on m'explique.
                Donc en fait dans le ttoriel, le code suivant :
                import java.util.ArrayList;
                 
                 
                public class Test {
                 
                        public static void main(String[] args) {
                                
                                ArrayList<Voiture> listVoiture = new ArrayList<Voiture>();
                                ArrayList<VoitureSansPermis> listVoitureSP = new ArrayList<VoitureSansPermis>();
                                
                                listVoiture = listVoitureSP;//Interdit ! ! ! ! 
                        }
                }
                

                Donc ce code pose un problème et je ne voit pas pourquoi on n'a pas le droit de faire ça étant donnée que l'on VoitureSansPermis qui hérite de Voiture.

                La solution qui est apporté ne m'éclaire pas, notamment la méthode afficher ou je ne comprend pas pourquoi est ce que l'on a un type entre le static et le void :

                import java.util.ArrayList;
                public class Test {
                 
                        public static void main(String[] args) {
                                
                                ArrayList<? extends Voiture> listVoitureSP = new ArrayList(); 
                                afficher(listVoitureSP);          
                        }
                        
                        /**
                         * Méthode générique !
                         * @param <T>
                         * @param list
                         */
                        static <T extends Voiture> void afficher(ArrayList<? extends Voiture> list){
                                for(Voiture v : list)
                                        System.out.println(v.toString());
                        }
                        
                }
                


                Merci de bien vouloir m'expliquer ça.
                • Partager sur Facebook
                • Partager sur Twitter
                  10 juillet 2008 à 1:43:22

                  quand tu fais
                  <T extends Class> dans une definition de methode ou de classe tu cree un type
                  la cysboy cree un type qu'il utilise jamais
                  je trouve ca bete ...

                  sinon apres je laisse le createur du tuto t'expliquer
                  je prefere m'abstenir ...
                  • Partager sur Facebook
                  • Partager sur Twitter
                    10 juillet 2008 à 11:35:59

                    C'est vrai que la déclaration de type ne sert à rien ici...
                    J'ai dû oublier de l'enlever :euh: : Je fais çà de suite.

                    Merci à vous.
                    • Partager sur Facebook
                    • Partager sur Twitter
                      10 juillet 2008 à 11:44:38

                      Voila la réponse que m'a donné CysBoy. J'ai tout compris du coup.

                      Je vais essayer de te répondre :

                      La généricité n'existe que lorsque la JVM compile le programme.
                      Lorsque tu as ce genre de class :
                      public class Paire<T, S>{
                         //CF exemple du tuto
                      }
                      


                      Lorsque tu utilise cette class, comme ceci par exemple :
                      Paire<String, Double> paireSD = new Paire<String, Double>("Toto", 12.01);

                      Les types T et S de la classe ne sont renseigné qu'à la compilation (on parle d'ereasure de la JVM, ou suppression de type générique). C'est à ce moment que la JVM va déterminé quels sont les types de l'objet.

                      Ceci est vrai aussi lorsque tu utilise la généricité sur des collections.
                      Lorsque tu paramètre des collections via la généricité, quelque soit les types utilisés, ils ne seront effectif pour a JVM qu'à la compilation.

                      Si on prend un exemple simple :
                      ArrayList<Double> listD = new ArrayList();
                      ArrayList<Object> listO = listD;
                      



                      La deuxième sera refusé par le compilateur !
                      Tu a paramétré une liste pour contenir des Double et une autre pour contenir des Object. Mais, avec la deuxième ligne tu dis que la liste d'Object va d'abord avoir des Double et que tu pourras aussi ajouter des Object par la suite !

                      Les types génériques (ou paramétrés) n'ont pas été pensés comme ça... Même si la class Double hérite d'Object.
                      Pour la JVM tu viole la contrainte d'intégrité, spécifié à la compilation, sur ta liste d'Object ! ! ^^
                      N'oublie pas que tu ne passe pas une variable d'un certain type dans une collection d'objet mais une liste paramétré ! Ce n'est pas le contenu de la liste qui porte le type de donnée mais la liste elle même !

                      Pour que la déclaration soit valide tu devras IMPERATIVEMENT spécifier à ta liste quelle devra contenir des types hérité, comme ceci :

                      ArrayList<Double> listD = new ArrayList();
                      ArrayList<? extends Object> listO = listD;
                      




                      Vu que c'est un des concepts les plus compliqué qu'il puisse y avoir en Java, ce n'est pas très facile à expliquer... Je ne sais pas si j'ai clarifié la situation pour toi mais bon... ^^

                      Sinon, si tu bloque sur ce point, ce n'est pas très grave...
                      • Partager sur Facebook
                      • Partager sur Twitter
                        9 janvier 2009 à 18:32:29

                        Niluge j'ai voulu juste te dire merci pour l'explication
                        • Partager sur Facebook
                        • Partager sur Twitter
                          28 mai 2009 à 10:14:12

                          Bonjour à tous, comme Niluge je suis en train de suivre de près le tutoriel, et je viens de tomber sur un petit problème.
                          Je code la classe Voiture, et la classe VoitureSansPermis mais au moment de faire le ArrayList j'ai un beau message d'erreur.


                          Voiture A = new VoitureSansPermis();
                          Voiture B = new VoitureSansPermis();
                          
                          ArrayList<? extends Voiture> liste = new ArrayList();
                          liste.add(A);
                          liste.add(B);
                          System.out.println(liste);
                          


                          Exception in thread "main" java.lang.Error: Unresolved compilation problem:
                          The method add(capture#1-of ? extends Voiture) in the type ArrayList<capture#1-of ? extends Voiture> is not applicable for the arguments (Voiture)


                          Et lorsque je change les deux première lignes pour du "VoitureSansPermis A" au lieu de "Voiture A" le message d'erreur est sensiblement le même.
                          • Partager sur Facebook
                          • Partager sur Twitter
                            28 mai 2009 à 11:25:06

                            ArrayList<? extends Voiture> liste = new ArrayList();
                            


                            Cette ligne devrait plutôt ressembler à :

                            ArrayList<? extends Voiture> liste = new ArrayList<? extends Voiture>();
                            


                            (Je ne garantis rien sur la syntaxe, j'utilise assez peu l'héritage+généricité)

                            Bref, le générique doit être indiqué à la déclaration de la variable, mais aussi à l'instanciation. Dans ton code, tu ne l'as indiqué qu'à la déclaration.
                            • Partager sur Facebook
                            • Partager sur Twitter
                            Anonyme
                              28 mai 2009 à 11:32:16

                              A et B sont des Voiture, pas des enfants de Voiture <? extends Voiture> n'est donc pas juste, il faut utiliser <Voiture>

                              c'est la déclaration qui compte, pas l'initialisation.
                              • Partager sur Facebook
                              • Partager sur Twitter

                              Héritage et généricité

                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                              • Editeur
                              • Markdown