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

Collection et Stream Java Discussion :

Généricité, collections et wildcards


Sujet :

Collection et Stream Java

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2011
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2011
    Messages : 179
    Points : 77
    Points
    77
    Par défaut Généricité, collections et wildcards
    Bonjour,

    j'ai un souci de compréhension concernant les wildcards (?) et la généricité pour les collections. Je comprends bien l'utilisation du wilcard dans le cas de figure où on veut utiliser le polymorphisme pour une méthode :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public void fonctionBidule(List<? extends Chose> list){
       ...
    }
    Par contre, je ne vois pas l'intérêt d'utiliser le wildcard pour l'initialisation ou la déclaration d'une Collection ?

    Quelle est la différence par exemple entre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    List<? extends Chose> list = new ArrayList<Chose>();
    et :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    List<Chose> list = new ArrayList<Chose>();
    Sachant que, à moins que je me trompe, dans les 2 cas de figure, on peut ajouter aux ArrayList des références à des classes ou sous classes de Chose ?

    Merci de m'aider à comprendre

  2. #2
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    ha non, dans le premier cas, on ne pourra rien ajouter, car on ne sais pas, a priori quel type concret stocke la liste

    L'intéret du premier cas et de pouvoir remplacer la liste par une autre si besoin. Exemple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    List<? extends Chose> list = new ArrayList<Chose>();
     
    public setListe(List<? extends Chose> list){
       this.list=list
    }
    //....
    instance.setListe(new ArrayList<Bidule>());//Bidule extends Chose
    alors que si on type exactement

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    List<Chose> list = new ArrayList<Chose>();
     
    public setListe(List<Chose> list){
       this.list=list
    }
    //....
    instance.setListe(new ArrayList<Bidule>());//erreur

  3. #3
    Membre habitué Avatar de dev_2007
    Profil pro
    Inscrit en
    Août 2007
    Messages
    98
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2007
    Messages : 98
    Points : 138
    Points
    138
    Par défaut
    Et je rajoute quelque intérêt des wildcard :

    - Le wildcard (?) permet de dire que n'importe quel type peut être traité et donc accepté !

    - Dès que le wildcard (?) est utilisé sur une collection, cela revient à rendre la dite collection en lecture seule !

    - L'instruction <? extends MaClasse> autorise toutes les collections de classes ayant pour super type MaClasse.
    Cordialement,
    HEL
    __________________
    Tout d'abord le faire fonctionner , Ensuite qu'il soit rapide. Enfin le rendre agréable à utiliser.

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2011
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2011
    Messages : 179
    Points : 77
    Points
    77
    Par défaut
    En fait, je me suis fais un petit exemple de test où j'ai crée une interface I, une classe Impl implémentant I et une classe ImplFille étendant Impl

    Ce code marche :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    List<Impl> list1 = new ArrayList<Impl>();
    list1.add(new Impl());
     
    List<ImplFille> list2 = new ArrayList<ImplFille>();
    list2.add(new ImplFille());
     
    list1.addAll(list2);
     
    List<? extends Impl> list3 = list1;

    En quoi est il différent svp de celui ci (qui marche aussi) ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    List<Impl> list1 = new ArrayList<Impl>();
    list1.add(new Impl());
    list1.add(new ImplFille());

  5. #5
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par jecomprendsrien Voir le message
    En quoi est il différent svp de celui ci (qui marche aussi) ?
    Je ne vois pas en quoi ils sont semblables. Ils sont différents en tout.

    Dans le second cas, tu as créé une seule List, contenue dans la variable list1, et elle contient deux objets.

    Dans le premier cas, tu as créé deux List, dans les variables list1 et list2, de sorte que list2 contienne un objet et list1 en contienne deux.
    Puis tu as déclaré une troisième variable list3 qui pointe vers list1.

    Dans les deux cas tu te retrouves avec une variable nommée list1, de type List<Impl> qui contient la même chose.
    À part ça, les deux cas n'ont pas de point commun. Puisqu'ils ne se ressemblent même pas, je dirais que leurs différences, c'est tout. Ils sont différents en tout. Il n'y a rien à comparer entre deux choses qui ne se ressemblent pas.

    Citation Envoyé par dev_2007 Voir le message
    - Le wildcard (?) permet de dire que n'importe quel type peut être traité et donc accepté !
    ?? Non... Il signifie qu'on ne sait pas ce que la collection contient. Par conséquent elle n'accepte aucun type (puisque quel que soit le type qu'on voudrait y mettre, on ne sait pas si c'est le bon, donc on ne peut pas.)
    Autre conséquence, ce qu'elle contient ne peut être traité que comme Object, le type parent à tous les types objets.

    Citation Envoyé par dev_2007 Voir le message
    - Dès que le wildcard (?) est utilisé sur une collection, cela revient à rendre la dite collection en lecture seule !
    Pas tout à fait. C'est le cas de <?> et de <? extends truc>. Vu qu'on ne sait pas ce que contient la collection, on ne peut rien mettre dedans, c'est logique.

    Mais avec <? super machin>, par contre, on peut y mettre des machin. Ce n'est donc pas en lecture seule.


    Citation Envoyé par dev_2007 Voir le message
    - L'instruction <? extends MaClasse> autorise toutes les collections de classes ayant pour super type MaClasse.
    Ça ne veut pas dire grand-chose, tout ça. On vient de dire qu'on ne peut rien mettre dans une collection qui fait <? extends MaClasse>.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    d'une manière générale, quand tu utilise le wildcard <?> ou <? extends ...> dans la déclaration d'une variable ou d'un champ:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    List<? extends Truc> maListe = new ArrayList<TrucBidule>();
    Comparator<?  extends Truc> monComparator = new MonComparator();
    tu t'interdis d'appeler toute méthode prenant ce type en paramètre. Ainsi, tu ne pourra pas appeler maListe.add(T) ni monComparator.compare(T,T). Par contre, tu peux toujours appeler des méthodes qui retournent ce type car, on sais, quelle retournent au moins un Truc. Exemple: Truc t = maListe.get(0);

    List<?> est l'équivalent de List<? extends Object>. Attention aussi à l'erreur commune. Déclarer List maliste; n'est pas la même chose que déclarer List<?> maliste; Dans le premier cas on précise au compilateur (et ça génère un warning) qu'il faut ignorer toute la logique des classes génériques. Dans le second cas on lui dit qu'on ignore quel type sera utilisé. A ce titre, le premier cas est beaucoup plus proche de List<Object> maliste


    Et comme le précise theElvin, <? super ...> fonctionne dans le sens inverse: tu pourra appeler des méthodes (car tu connais des types compatibles), mais le retour seront tous de type Object au mieux

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2011
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2011
    Messages : 179
    Points : 77
    Points
    77
    Par défaut
    Salut,

    alors là honnêtement...je comprends de moins en moins

    Dans mon dernier message, je demandais juste en fait si list3 était semblable à list1 du dessous ?

    En effet, j'arrive pas saisir la différence entre List<Truc> et List<? extends Truc>. Pour moi, on peut mettre toutes les sous classes de Truc et Truc compris dans les 2 List...non ? La seule différence que je vois c'est que List<? extends Truc> pose un verrou en insertion une fois la List initialisée

    @thelvin : quand tu dis : Il signifie qu'on ne sait pas ce que la collection contient en parlant du wildcard, tu veux dire qu'on ne sait pas ce que la collection contient dans le sous ensemble de classes représenté par Truc et ses sous classes en fait ? Je saisis pas la différence avec List<Truc> car on peut y mettre Truc et ses sous classes aussi non ?

    En fait j'ai juste saisi l'utilisation de <? extends Truc> au lieu de <Truc> dans les arguments des fonctions pour élargir en quelque sorte leur domaine d'action et ne pas limiter le passage d'argument à Truc uniquement mais aussi à ses sous classes...à part ça je suis dans le flou

    @tchize_ : désolé j'ai rien compris à ton premier paragraphe

    Merci pour votre aide en tout cas

  8. #8
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par jecomprendsrien Voir le message
    Dans mon dernier message, je demandais juste en fait si list3 était semblable à list1 du dessous ?
    Semblable oui, mais il y a une différence : tu peux ajouter des éléments à list1, alors que tu ne peux pas en ajouter à list3.

    Citation Envoyé par jecomprendsrien Voir le message
    En effet, j'arrive pas saisir la différence entre List<Truc> et List<? extends Truc>.
    Eh ben je viens de le dire.

    Citation Envoyé par jecomprendsrien Voir le message
    Pour moi, on peut mettre toutes les sous classes de Truc et Truc compris dans les 2 List...non ? La seule différence que je vois c'est que List<? extends Truc> pose un verrou en insertion une fois la List initialisée
    Il pose un verrou en insertion, tout court. Peu importe que ce soit après initialisation ou je ne sais quoi.

    En fait c'est un peu plus général qu'un "verrou en insertion."

    Quand on fait Machin<? extends Truc>, on peut en récupérer des Truc, mais on ne peut pas lui donner des Truc. On ne peut pas appeler ses méthodes qui prennent des Truc en paramètre.
    Dans le cas des Collections ça l'empêche, en effet, de prendre de nouveaux objets (on ne peut pas appeler les méthodes qui insèrent de nouveaux objets).
    Mais il n'y a pas que les collections dans la vie, le même mécanisme marche avec tout.

    Citation Envoyé par jecomprendsrien Voir le message
    @thelvin : quand tu dis : Il signifie qu'on ne sait pas ce que la collection contient en parlant du wildcard, tu veux dire qu'on ne sait pas ce que la collection contient dans le sous ensemble de classes représenté par Truc et ses sous classes en fait ? Je saisis pas la différence avec List<Truc> car on peut y mettre Truc et ses sous classes aussi non ?
    Alors déjà je parlais de <?> et pas de <? extends Truc>.
    List<?> signifie List de on ne sait pas quoi.

    Quant à la différence entre List<Truc> et List<? extends Truc>, je te l'ai déjà dit : dans le premier on peut y mettre des Truc. Dans le second on ne peut pas.

    Parce que dans le premier on sait que c'est une List de Truc, donc on peut y mettre des Truc.
    Dans le second c'est une List d'on ne sait pas quoi mais qui, en tout cas, étend Truc. On ne peut pas y mettre de Truc, ni rien d'autre, parce qu'on ne sait pas ce que cette List a le droit de contenir. On sait juste que quoi que ce soit, c'est un sous-type valide de Truc.

    Citation Envoyé par jecomprendsrien Voir le message
    En fait j'ai juste saisi l'utilisation de <? extends Truc> au lieu de <Truc> dans les arguments des fonctions pour élargir en quelque sorte leur domaine d'action et ne pas limiter le passage d'argument à Truc uniquement mais aussi à ses sous classes...à part ça je suis dans le flou
    Il n'y a pas de "à part ça." Ça sert à ça et rien d'autre.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2011
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2011
    Messages : 179
    Points : 77
    Points
    77
    Par défaut
    Citation Envoyé par thelvin Voir le message
    Parce que dans le premier on sait que c'est une List de Truc, donc on peut y mettre des Truc.
    Dans le second c'est une List d'on ne sait pas quoi mais qui, en tout cas, étend Truc. On ne peut pas y mettre de Truc, ni rien d'autre, parce qu'on ne sait pas ce que cette List a le droit de contenir. On sait juste que quoi que ce soit, c'est un sous-type valide de Truc.
    c'est ça que je pige pas. Dans le premier cas, on sait que c'est une List de Truc ok mais ça peut être aussi une List de Truc et de ses sous classes car rien ne m'empeche d'y ajouter un TrucMachin ou un TrucBidule tous 2 sous classes de Truc ? Donc ça revient au même que <? extends Truc> mis à part que c'est pas verrouillé

    Dans quel cas de figure concret par exemple dois je utiliser l'une ou l'autre forme ?

    Merci encore

  10. #10
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Tout d'abord deux classes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class Truc{
    public void f(){}
    }
     
    class Bidule extends Truc{
    public void g(){}
    }
    Maintenant quelques listes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    List<Truc> trucs = new LinkedList<Truc>();
    trucs.add(new Truc());
    trucs.add(new Bidule());
     
    List<Bidules> bidules = new LinkedList<Bidules>();
    bidules.add(new Bidule());
    bidules.add(new Bidule());
    Et enfin, quelques utilisations:
    [code]void fOnTrucs(List<Truc> trucs){
    for(Truc truc : trucs) truc.f();
    }
    void fOnPlusQueTrucs(List<? extends Truc> plusQueTrucs){
    for(Truc plusQueTruc : plusQueTrucs) plusQueTruc.f();
    }
    void gOnBidules(List<Bidule> bidules){
    for(Bidule bidule : bidules) bidule.g();
    }[code]

    Avec ca, voici ce qui est possible:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    fOnTrucs(trucs);
    fOnPlusQueTrucs(trucs);
    fOnPlusQueTrucs(bidules);
    gOnBidules(bidules);
    mais aucune des instructions suivantes n'est valide:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    fOnTrucs(bidules);//List<Bidule> is NOT List<Truc>
    gOnBidules(trucs);//List<Truc> is NOT List<Bidule>
    Donc si j'ai une List<Bidule>, je peux utiliser toutes les fonctions utilisant List<Bidule> (et donc g()), mais aucune List<Truc>.
    Le type qui a codé fOnTruc() m'empeche d'utiliser sa fonction parce que j'ai une liste de "PlusQueTruc" (? extends Truc), ici Bidule


    Personnellement, j'utiliserais des variables locales List<Truc> et List<Bidules>, mais les arguments de mes fonctions seront List<? extends Truc> et List<? extends Bidule>.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  11. #11
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par jecomprendsrien Voir le message
    En effet, j'arrive pas saisir la différence entre List<Truc> et List<? extends Truc>. Pour moi, on peut mettre toutes les sous classes de Truc et Truc compris dans les 2 List...non ?
    Non, c'est là ton erreur. Je pense qu'un exemple sera plus parlant pour que tu comprenne où tu pêche

    Supposons Machin et Bidule extends Truc

    1er cas, List<Truc>, tout va bien

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    List<Truc> maListe = new ArrayList<Truc>();
    maListe.add(new Machin());
    maListe.add(new Bidule());
    Truc t = maListe.get(0);
    deuxième cas, la wildcard
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    List<Bidule> maListe = new ArrayList<Bidule>();
    List<? extends Truc> autreListe = maListe; // là c'est bon, c'est compatible d'après le langage
    autreListe.add(new Machin()); // imaginons que ce soit autorisé car Machin est un Truc
    Bidule b = maListe.get(0); // j'ai un gros problème, une List<Bidule> va me retourner un Machin!!
    Il faut bien voir que <? extends Truc> ne veux pas dire "n'importe quoi qui est Truc ou un sous type" mais "Quelque chose que j'ignore qui est Truc ou un sous type". Cette différence est fondamentale! Dans l'exemple que je t'ai donné, le "quelque chose", c'est Bidule, et ça doit empecher de mettre des Machin, et donc tu toi considérer que "quelque chose", ce n'est pas assez précis et ça interdit d'utiliser la méthode C'est ce que fait le langage.

  12. #12
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2011
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2011
    Messages : 179
    Points : 77
    Points
    77
    Par défaut
    Bien vu pour l'exemple tchize_ je crois que j'ai capté les différences entre les 2 types et surtout pourquoi on ne peut pas ajouter de nouveaux éléments dans une List avec wilcard

    Merci encore je pense que mon problème est résolu, maintenant je vais forger pour devenir forgeron marre de pêcher ^^

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

Discussions similaires

  1. Conversions, collections et généricité
    Par whims dans le forum Langage
    Réponses: 3
    Dernier message: 30/12/2010, 13h34
  2. Généricité et fonction Collections.sort
    Par Matthiews dans le forum Collection et Stream
    Réponses: 4
    Dernier message: 23/07/2010, 09h38
  3. Pb de conception avec collection / objet et généricité
    Par MrEddy dans le forum Général Java
    Réponses: 5
    Dernier message: 16/06/2010, 14h36
  4. Question sur la généricité et les Collections
    Par MrEddy dans le forum Général Java
    Réponses: 4
    Dernier message: 11/06/2010, 11h39
  5. HashMap, généricité, wildcard, héritage, extension
    Par kenji_getpowered dans le forum Collection et Stream
    Réponses: 2
    Dernier message: 01/04/2010, 17h40

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