Partage
  • Partager sur Facebook
  • Partager sur Twitter

Méthode add et généricité

Sujet résolu
    6 novembre 2008 à 12:16:25

    Bonjour à tous !

    Je vous explique le problème de façon rapide:
    Ayant repris les cours Java (peu de pratique), je me retrouve confronté à un problème lors d'un ajout d'un élément d'une classe personnalisé dans une collection de type ArrayList.
    En effet, j'utilise un wildcard afin de permettre à l'arraylist d'accepter tout type hérité d'une classe Voiture (je suis sur l'exemple du tuto officiel) ou du type en lui-même.
    Tout fonctionne, excepté lors de l'ajout d'un élément. Apparemment, la méthode add n'aime pas le type-là.

    Voici le code de main:
    import java.util.ArrayList;
    
    public class tp0
    {
    	public static void main(String[] args) {
    		ArrayList<? extends Voiture> listVoitures = new ArrayList<Voiture>();
    		listVoitures.add(new Voiture("rouge"));
    		afficher(listVoitures);
    	}
    	
    	static void afficher(ArrayList<? extends Voiture> listing)
    	{
    		for(Voiture v : listing)
    		{
    			System.out.println(v);
    		}
    	}
    }
    

    J'ai une classe "Espace" héritée de Voiture. Dans Voiture, j'ai une méthode toString, afin d'afficher lisiblement l'instance.
    J'ai rajouté <Voiture> sur le new ArrayList car Eclipse a réclamé une définition explicite du type, et que je la mette ou non, l'erreur reste la même (ça semble donc indépendant de cela).
    A noter que j'ai testé en faisant un cast depuis Voiture vers Object, sans résultat (une erreur de cast est alors apparue).

    L'erreur est à la ligne:
    listVoitures.add(new Voiture("rouge"));
    

    The method add(capture#7-of ? extends Voiture) in the type ArrayList<capture#7-of ? extends Voiture> is not applicable for the arguments (Voiture)


    Quelqu'un aurait-il une solution ?

    Merci d'avance :)
    • Partager sur Facebook
    • Partager sur Twitter
      6 novembre 2008 à 14:23:33

      voiture est une interface ?
      • Partager sur Facebook
      • Partager sur Twitter
        6 novembre 2008 à 14:40:41

        Non, il s'agit simplement d'une autre classe de laquelle hérite une classe Espace.
        • Partager sur Facebook
        • Partager sur Twitter
          6 novembre 2008 à 14:59:21

          Comment cela ?
          Le wildcard <? extends Voiture> signifie bien "pour tous les types Voiture et les classes héritées ou implémentées", non ?
          • Partager sur Facebook
          • Partager sur Twitter
            6 novembre 2008 à 15:00:22

            la classe Voiture n'implemente pas l'interface Voiture ;)
            • Partager sur Facebook
            • Partager sur Twitter
              6 novembre 2008 à 15:19:44

              o_O
              Mais Voiture n'est pas une interface. On est donc obligé de créer et implémenter une interface "bidon" X si on veut utiliser des collections avec généricité, utilisé avec la classe X ?
              Parce qu'en implémentant une interface Voiture qui n'existe pas, j'ai (bien entendu) une erreur.

              Si c'est le cas, y'a un souci avec le tuto officiel Java >__<
              • Partager sur Facebook
              • Partager sur Twitter
                6 novembre 2008 à 15:32:42

                oui, une interface genre vehicule
                • Partager sur Facebook
                • Partager sur Twitter
                  6 novembre 2008 à 15:35:44

                  o_O
                  J'aimerais quand même savoir pourquoi, si possible. Parce que ce n'est pas vraiment logique.
                  Mais bon, vais tester pour voir, déjà.

                  EDIT: Même en créant une interface "Vehicule" implémentée pour Voiture, ça ne fonctionne pas. Ca me rassure un poil, quand même, parce que sinon c'était réellement pas logique...
                  • Partager sur Facebook
                  • Partager sur Twitter
                    6 novembre 2008 à 15:43:01

                    heu si tu as une interface I implementee par A, et B
                    tu pourras stockerles deux dans une collection tel:

                    ArrayList<? extends I>

                    a moins que je me trompe .. ca fais lontemps que j'ai pas essaye

                    EDIT:

                    Je me trompe en effet... je cherche parce que la je suis perplexe


                    EDIT:

                    interface test {
                    	public void myTest();
                    }
                    
                    class A implements test {
                    
                    	public void myTest() {
                    		// TODO Auto-generated method stub
                    
                    	}
                    
                    }
                    
                    class B implements test {
                    
                    	public void myTest() {
                    		// TODO Auto-generated method stub
                    
                    	}
                    
                    }
                    
                    	public Main() {
                    		ArrayList<test> array = new ArrayList<test>();
                    		array.add(new A());
                    
                    	}
                    



                    ca ca marche...



                    • Partager sur Facebook
                    • Partager sur Twitter
                      6 novembre 2008 à 16:03:25

                      Si je reprends ton exemple, cela plante sur la méthode statique, car j'explore un objet Vehicule considéré comme Voiture, et cast impossible (caster une interface vers le type qui l'implémente ne passe apparemment pas).
                      Par contre, je vais tester avec une classe abstraite Vehicule dont Voiture hérite et changer le wildcard en <? extends Vehicule> pour voir si, des fois, ce wildcard ne prend pas en compte la classe en elle-même mais que ses classes-filles. Mais ça reste louche.

                      Pas de changements avec cette opération... Je ne comprends réellement pas le problème, là...

                      EDIT: codes modifiés:
                      main:
                      import java.util.ArrayList;
                      
                      public class tp0
                      {
                      	public static void main(String[] args) {
                      		
                      		ArrayList<? extends Vehicule> listVoitures = new ArrayList();
                      		listVoitures.add(new Voiture("rouge"));
                      		afficher(listVoitures);
                      		
                      	}
                      	
                      	static void afficher(ArrayList<? extends Vehicule> listing)
                      	{
                      		for(Vehicule v : listing)
                      		{
                      			System.out.println(v);
                      		}
                      	}
                      }
                      


                      Voiture:
                      public class Voiture extends Vehicule {
                      	protected int nbRoues;
                      	protected int nbPlaces;
                      	protected String couleur;
                      	
                      	public Voiture(String col)
                      	{
                      		this.nbRoues = 4;
                      		this.nbPlaces = 4;
                      		this.couleur = col;
                      	}
                      	
                      	public String toString()
                      	{
                      		String res = "Je suis une Voiture avec "+this.nbRoues+" roues, "+this.nbPlaces+" places et je suis "+this.couleur+" !";
                      		return res;
                      	}
                      }
                      
                      • Partager sur Facebook
                      • Partager sur Twitter
                        6 novembre 2008 à 16:10:05

                        je viens de regarder un peu avec le wildcard, je voyais pas la chose comme ceci

                        Je suis plutot habituer a utiliser des truc du genre : <T extends SomeThing>

                        Sinon tu avais raison quant au fait que <? extends Voiture> represente toutes les classes fille de voitures

                        J'ai fait des recherche :

                        Citation : Pas de titre

                        List<? extends Shape> is an example of a bounded wildcard. The ? stands
                        for an unknown type, just like the wildcards we saw earlier. However, in this case, we
                        know that this unknown type is in fact a subtype of Shape1 . We say that Shape is the
                        upper bound of the wildcard.
                        There is, as usual, a price to be paid for the flexibility of using wildcards. That price
                        is that it is now illegal to write into shapes in the body of the method. For instance,
                        this is not allowed:

                        public void addRectangle(List<? extends Shape> shapes) {
                                shapes.add(0, new Rectangle()); // compile-time error!
                             }
                        


                        You should be able to figure out why the code above is disallowed. The type of
                        the second parameter to shapes.add() is ? extends Shape - an unknown subtype
                        of Shape. Since we don’t know what type it is, we don’t know if it is a supertype
                        of Rectangle; it might or might not be such a supertype, so it isn’t safe to pass a
                        Rectangle there.



                        • Partager sur Facebook
                        • Partager sur Twitter
                          6 novembre 2008 à 16:23:21

                          Arf, donc ce n'est en fait pas supporté actuellement, pour éviter des problèmes éventuels.
                          Dommage, du coup ça limite un peu le truc, obligé de faire des collections d'Object et de faire du cast à l'affectation...

                          Merci tout de même ;)

                          Je place le sujet en résolu.
                          • Partager sur Facebook
                          • Partager sur Twitter
                            6 novembre 2008 à 17:42:40

                            Tu ne peux pas mettre simplement List<Voiture> ?
                            En toute logique si c'est une sous-classe ça devrait prendre...
                            • Partager sur Facebook
                            • Partager sur Twitter
                              6 novembre 2008 à 21:52:45

                              ouais ^^ mais le pb est interressant
                              • Partager sur Facebook
                              • Partager sur Twitter
                                6 novembre 2008 à 22:07:29

                                Dites, je vais sûrement dire une bêtise parce que je n'utilise pas souvent les wildcards, mais pour une interface dans tous les cas faut mettre implements non ?
                                Ensuite avec l'héritage, indiquer seulement Voiture devrait marcher oui...
                                Je vais faire un tour dans Java en concentré et j'edit, parce que là ça me paraît bizarre quand même le problème.
                                Et si tu instancies ton objet Voiture en dehors de la méthode add, ça ne fonctionne pas ?

                                Edit: Oui non j'ai rien dit. Faudrait que j'étudie la généricité plus en détails.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  6 novembre 2008 à 22:24:15

                                  Citation

                                  Dites, je vais sûrement dire une bêtise parce que je n'utilise pas souvent les wildcards, mais pour une interface dans tous les cas faut mettre implements
                                  non ?


                                  Non, dans ce cas c'est extends, qu'il s'agisse d'une classe ou d'une interface. Les concepteurs du langage n'ont pas jugé nécessaire de faire la distinction dans le cadre de la généricité.

                                  Je dois sûrement passer pour un imbécile, mais je ne comprends pas la différence qu'il y a entre List<Voiture> et List<? extends Voiture> dans l'exemple qui nous intéresse ici, puisque la seule indication <Voiture> accepte aussi de fait n'importe quelle sous-classe. Je ne vois pas l'utilité d'avoir recours aux wildhcars ici. Qu'est-ce qu'on a voulu exprimer de plus ?
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    6 novembre 2008 à 23:17:13

                                    Comment cela ? Ca veut dire qu'en indiquant <Voiture>, on accepte également les classes qui héritent de Voiture (j'ai une classe Espace qui hérite de Voiture, dans mon cas, d'où l'utilisation du wildcard) ? En ce cas, quelle est l'utilité du wildcard <? extends autre que l'utilisation des interfaces ?
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      7 novembre 2008 à 1:00:52

                                      Citation : Lpu8er

                                      Comment cela ? Ca veut dire qu'en indiquant <Voiture>, on accepte également les classes qui héritent de Voiture ?


                                      Je ne suis pas un spécialiste, mais la réponse est oui il me semble. C'est le principe du polymorphisme. Une Espace "est une" Voiture, donc là où on attend une Voiture on peut très bien y mettre une Espace.

                                      Du coup, moi non plus je ne vois pas trop l'intérêt de ce fameux wildcard (dans le livre que j'ai on parle de joker) dont j'ignorais l'existence jusqu'à aujourd'hui. Mais il y en a sûrement un et ça serait vraiment intéressant de le connaître.
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        7 novembre 2008 à 6:29:14

                                        Citation

                                        En ce cas, quelle est l'utilité du wildcard <? extends autre que l'utilisation des interfaces ?


                                        ET même avec les interfaces c'est discutable... Essaie List<Comparable>. Tu verras que tu peux mettre des Integer, des Double et des String... L'exemple est mal choisi et n'a aucun intérêt mais en mettant <Interface> on accepte aussi de fait toutes les classes qui implémentent cette interface.
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          7 novembre 2008 à 8:29:30

                                          Ah, donc au final, le wildcard <? extends ... > ne sert à rien, si ce n'est à expliciter < ... >, et encore, puisque cela ne fonctionne pas...

                                          Vais tester tout cela, en tout cas, merci encore !
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            7 novembre 2008 à 9:00:31

                                            Citation


                                            Ah, donc au final, le wildcard <? extends ... > ne sert à rien


                                            De mon point de vue effectivement, il ne sert à rien. Mais s'il existe c'est qu'il a forcément une utilité.

                                            Règle de base en lingustique : s'il y a deux expressions qui existent pour dire la même chose, c'est qu'il y a forcément une différence quelque part. Dans le cas contraire une des deux expressions tend logiquement à disparaître au profit de l'autre. C'est le principe de la sélection naturelle.
                                            Spécial dédicace à mon ex prof d'anglais du lycée.

                                            Bon, je m'écarte. Je conçois bien le <T extends Truc & Machin & Bidule> en déclarant une classe ou une méthode générique. La signification en est claire.
                                            Je serais ravi de connaître l'intérêt du <? extends Truc> pour ce cas précis et d'une manière générale, parce que je ne vois vraiment pas où ça peut s'appliquer.
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              7 novembre 2008 à 9:47:16

                                              Oui effectivement, cela fonctionne sans problème avec une classe héritée, avec un simple <Voiture>.

                                              Je serais aussi curieux que toi de voir pour cette histoire de <? extends...
                                              Mais laissons couler ce sujet, il y en a d'autres qui viennent ^^
                                              • Partager sur Facebook
                                              • Partager sur Twitter

                                              Méthode add 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