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 :

Mettre une valeur dans un Set<? extends String>


Sujet :

Langage Java

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    190
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 190
    Points : 153
    Points
    153
    Par défaut Mettre une valeur dans un Set<? extends String>
    Bonjour,

    Tout le problème est dans le titre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
       Set<? extends String> s;
       s.add("a");
    Provoque un message d'erreur pas très simple à comprendre.

    J'ai quand même réussi à ajouter un élément dans s:
    mais ce n'est pas très util.

    Ma question est donc: est-il possible de mettre des valeurs dans mon ensemble s? Si oui, comment? Sinon, un 'Set<? extends String>' n'est-il qu'un jouet théorique ou a-t-il une utilité?

    Remarquons que l'on peut supprimer des éléments de s car la méthode remove attend un Object en paramètre.

    Merci de vos réponses.

  2. #2
    Membre chevronné
    Avatar de afrikha
    Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    1 600
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2005
    Messages : 1 600
    Points : 2 208
    Points
    2 208
    Par défaut
    Bonjour,

    Citation Envoyé par LGnord Voir le message


    Provoque un message d'erreur pas très simple à comprendre.
    .
    Lequel ?

    Sinon la classe String étant final, elle ne peut être étendue, je ne vois donc pas l'intérêt de <? extends String>, un <String> suffira

    @+


    Mes publications
    Lisez
    Les régles du forum
    Pensez au bouton

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    190
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 190
    Points : 153
    Points
    153
    Par défaut
    afrikha, merci pour ta réponse.

    Le message d'erreur est le suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    The method add(capture-of ? extends String) in the type Set<capture-of ? extends String> is not  applicable for the arguments (String)
    C'est donc un problème de typage.

    La remarque sur le type String est trés pertinente mais elle ne m'aide pas. En effet, j'ai pris cet exemple pour poster mais j'ai le problème avec un type qui n'est pas final.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class A{}
     
    java.util.Set<? extends A > s;
    s.add(new A());
    Et le message d'erreur:
    The method add(capture-of ? extends A) in the type Set<capture-of ? extends A> is not applicable for the arguments (A)

  4. #4
    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,


    Citation Envoyé par LGnord Voir le message
    Et le message d'erreur:
    The method add(capture-of ? extends A) in the type Set<capture-of ? extends A> is not applicable for the arguments (A)
    C'est tout à fait normal : tu ne connais pas le type exact des éléments de ton Set. Tu sais juste qu'il s'agit d'objet héritant de A (ou A lui-même).

    La notation ? extends permet donc une espèce d'accès en lecture seulement : tu ne connais pas le type réel, mais tu connais un de ses types "parents". Ainsi tu peux lire les élements du Set (il seront forcément du type de A) mais tu ne peux pas y ajouter des éléments car tu ne connais pas le type précis des éléments du Set.


    Imagine que tu ais une classe fille B qui hérite de A, tu écrires ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    java.util.Set<? extends A > s = new HashSet<B>();
    Si le compilateur te laissait ajouter un élement de type A :
    Tu te retrouverais dans un état incohérent puisque tu ajoutes un objet de type A dans un Set<B> ce qui ne doit pas être possible !




    La question a se poser est plutôt : Pourquoi utiliser ? extends A et que cherches-tu a faire avec cela ?


    a++

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    190
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 190
    Points : 153
    Points
    153
    Par défaut
    Merci adiGuba, ton explication est très claire.

    Tu te retrouverais dans un état incohérent puisque tu ajoutes un objet de type A dans un Set<B> ce qui ne doit pas être possible !
    A la différence des tableaux qui ont une gestion à run-time (ArrayStoreException), c'est la compilation qui nous interdit de mélanger des A et des B dans un ensemble.

    La notation ? extends permet donc une espèce d'accès en lecture seulement.
    Je peux donc lire dans mon ensemble mais pas y écrire. Il m'est donc complétement inutil.

    Pourquoi utiliser '? extends A'?
    Je vais voir si je peux m'en passer.
    Mais il doit quand même exister des cas où utiliser un type paramètré par '? extends A' est util?

  6. #6
    Expert éminent
    Avatar de djo.mos
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    4 666
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 4 666
    Points : 7 679
    Points
    7 679
    Par défaut
    Bonjour,
    Citation Envoyé par LGnord Voir le message
    Mais il doit quand même exister des cas où utiliser un type paramètré par '? extends A' est util?
    Yep, pour pouvoir lui affecter une Liste de B avec B étend A.
    Si tu déclares ta liste comme List<A>, lui affecter un ArrayList<B> te donnerait une erreur de compile car même si B étend A, List<B> n'a aucun lien avec List<A>.

    Tu utilise ce genre de déclarations quand:
    - Il s'agit de lecture seule.
    - Tu veux donner plus de flexibilité à l'utilisateur quand il doit te fournir une liste.

    Pour pouvoir écrire dans une liste de ce type, il faut plutôt passer par <? super A>.

  7. #7
    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 LGnord Voir le message
    Mais il doit quand même exister des cas où utiliser un type paramètré par '? extends A' est util?
    Dans plein de cas : le problème lorsque tu utilises Set<A> c'est que tu n'est plus du tout générique puisque justement fortement typé !





    Prenons un autre exemple, mettons que nous avons une classe Person contenant principalement le nom et l'email de la personne (avec les accesseurs qui vont bien), et plusieurs classes filles qui gère des spécificités pour les clients, fournisseurs ou encore les employées via les sous-classes Customer, Supplier et Employee.


    L'application ou les applications pourraient être amenés à utiliser plusieurs types de collections :
    • Set<Person> lorsqu'on manipule plusieurs types de personnes différents.
    • Set<Customer> pour le service client.
    • Set<Supplier> pour la gestion des achats auprès des fournisseurs.
    • Set<Employee> pour la payes...



    Dans une classe utilitaire on voudrait permettre d'envoyer un simple mail à un ensemble de destinataire. On serait tenter d'écrire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    	public static void sendMail(String text, Set<Person> recipients) {
     
    		Email email = ... // une classe qui gère les emails
     
    		for (Person p : recipients) {
    			email.addRecipient(p.getEmail());
    		}
     
    		email.setContent(text);
    		email.send();
    	}

    Le problème c'est qu'on est fortement typé et qu'un Set<Customer> n'est pas un Set<Person>... On ne pourra donc pas utiliser notre méthode aussi facilement que possible et il faudra soit dupliqué du code, soit effectué diverses transformations plutôt inutile.


    Or dans notre méthode sendMail() on se fiche de connaitre le type exact de la liste, du moment qu'il s'agit bien d'une liste de personnes...

    En changeant simplement la déclaration du paramètre générique on corrige directement ce petit problème :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public static void sendMail(String text, Set<? extends Person> recipients) {
    On peut désormais utiliser notre méthode avec n'importe quel type de liste de personnes, quelque soit le type précis de la liste

    En contrepartie on ne peut pas modifier la liste mais c'est logique puisqu'on ne connait pas exactement le type de la liste !





    Le ? super T permet exactement l'inverse, mais l'intérêt est un peu moins évident à comprendre...



    Il ne faut pas oublier non plus qu'avec les méthodes Generics ont peut avoir des liens entre les types des différents paramètres. Par exemple la méthode Collections.copy() déclaré de la manière suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public static <T> void copy(List<? super T> dest, List<? extends T> src)
    Permet de copier tous les éléments d'une liste de T (ou de type fils) vers une liste d'un type quelquonque mais parent de T (qui peut donc comporter des éléments du type T).

    Ce qui fait que les types des deux listes ne doivent pas impérativement être du même type, mais doivent rester cohérente, par exemple ceci est possible :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	List<Number> listNumber = ...
    	List<Double> listDouble = ...
     
    	Collections.copy(listNumber, listDouble);
    Mais pas l'inverse !



    Si on n'aurait pas utiliser les wildcard, et qu'on se serait contenter de ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public static <T> void copy(List<T> dest, List<T> src)
    Le code ci-dessus n'aurait pas été possible et les deux List auraient dû être exactement du même type Générics...




    Ce n'est pas forcément évident à comprendre, mais les wildcards ont un gros intérêt dans les Generics, et peut-être même que tu as déjà utilisé des méthodes les utilisant sans t'en apercevoir

    a++

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

Discussions similaires

  1. Réponses: 9
    Dernier message: 01/04/2014, 07h57
  2. [XL-2003] Probleme pour mettre une valeur dans la cellule voulue
    Par tools dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 07/06/2011, 15h46
  3. Mettre une valeur dans un TEdit
    Par medkyl dans le forum Débuter
    Réponses: 4
    Dernier message: 09/11/2010, 14h20
  4. mettre une valeur dans une combobox
    Par lila23 dans le forum GWT et Vaadin
    Réponses: 1
    Dernier message: 06/07/2009, 17h51
  5. Mettre une Valeur dans un OptionBouton quand un autre OB est activé?
    Par muska78 dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 09/06/2008, 10h51

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