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 :

[Problème] avec les generics


Sujet :

Langage Java

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 7
    Points : 3
    Points
    3
    Par défaut [Problème] avec les generics
    Bonjour à tous,

    J'ai un problème assez sympa à vous exposer, qu'il faut que je resolve pour l'appli sur laquelle je travaille en ce moment.
    Mon appli utilise de plugins et ces plugins ont besoins de pouvoir déclarer un nombre inconnu de paramètres de types numérique bornés.

    J'ai une classe paramètre, et j'aurais voullu que celle-ci soit générique et puisse accepter tout type de "numérique" "comparable".
    J'ai donc écris ça (j'ai vonlontairement zappé les accesseurs et ... pour que ca soit lisible) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public class PluginsParameter<T extends Number & Comparable<T>> {
    	public String name;
    	public String description;
    	public T value;
    	public T minimum;
    	public T maximum;
    }
    Ensuite j'aurais voulu contruire une classe contenant une liste de cette bebête (PluginsParameter), et disposant de méthode de lecture, d'ajout, de suppression, ... pour rendre la manipulation des PluginsParameter plus aisée depuis les plugins.
    Mais là je galère.

    Pour l'instant j'ai ça :

    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
    public class PluginsParametersList {
     
    	private Map<String, PluginsParameter> list = new HashMap<String, PluginsParameter>( ); 
     
    	public <T extends Number & Comparable<T>> void put(String name, T value, T minimum, T maximum){
    		if(list.containsKey(name)){
    			list.remove(name);
    		}
    		list.put(name, new PluginsParameter2<T>(name, value, minimum, maximum));
    	}
     
    	public <T extends Number & Comparable<T>> T get(String name){
    		return list.get(name).getValue();
    	}
     
    	public void remove(String name){
    		if(list.containsKey(name)){
    			list.remove(name);
    		}
    	}
     
    	public boolean contains(String name){
    		return list.containsKey(name);
    	}
    }
    Premièrement : je n'arrive pas à typer correctement ma liste.
    Deuxièmement : je n'arrive pas à écrire une méthode "get" qui renvoi le type effectif, j'arrive avec difficulté à renvoyer un Number, ce qui ne m'aide pas beaucoup.

    Un peu (ou beaucoup) d'aide serait la bienvenue.
    Merci d'avance.

  2. #2
    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 Prodejeu
    Premièrement : je n'arrive pas à typer correctement ma liste.
    Comme tu l'utilise, il faudrait que tu la types fortement, du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    private Map<String, PluginsParameter<Integer>> list = new HashMap<String, PluginsParameter<Integer>>( );
    Seulement je ne pense pas que ce soit ce dont tu as besoins, puisque tu souhaites conserver de la généricité à ce niveau là.

    Pour moi il faudrait que ta classe PluginsParameterList utilise également les Generics (et non pas seulement ses méthodes). Du coups cela devient plus simple :
    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
    public class PluginsParametersList<T extends Number & Comparable<T>> {
     
        private Map<String, PluginsParameter<T>> list = new HashMap<String, PluginsParameter<T>>( ); 
     
        public void put(String name, T value, T minimum, T maximum){
            if(list.containsKey(name)){
                list.remove(name);
            }
            list.put(name, new PluginsParameter<T>(name, value, minimum, maximum));
        }
     
        public T get(String name){
            return list.get(name).getValue();
        }
     
        public void remove(String name){
            if(list.containsKey(name)){
                list.remove(name);
            }
        }
     
        public boolean contains(String name){
            return list.containsKey(name);
        }
    }
    Citation Envoyé par Prodejeu
    Deuxièmement : je n'arrive pas à écrire une méthode "get" qui renvoi le type effectif, j'arrive avec difficulté à renvoyer un Number, ce qui ne m'aide pas beaucoup.
    Cela devrait être réglé puisque la Map est correctement typé...



    Enfin petit "conseil", tu pourrais implémenter l'interface Iterable de la manière suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class PluginsParametersList<T extends Number & Comparable<T>> implements Iterable<PluginsParameter<T>>{
     
        private Map<String, PluginsParameter<T>> list = new HashMap<String, PluginsParameter<T>>( );
     
        public Iterator<PluginsParameter<T>> iterator() {
            return this.list.values().iterator();
        }
     
    ...
    Cela te permet d'utiliser tes objets PluginsParametersList dans la nouvelle boucle for :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
            PluginsParametersList<Integer> list = ...;
     
            for (PluginsParameter<Integer> param : list) {
                // ...
            }
    C'est vraiment très pratique et pas complexe à mettre en place

    a++

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Citation Envoyé par adiGuba
    Pour moi il faudrait que ta classe PluginsParameterList utilise également les Generics (et non pas seulement ses méthodes).
    Effectivement ca corrige les erreurs, mais au final je suis obligé de typer fortement PluginsParameterList au moment de sa déclaration, ce qui ne fait que déplacer le problème.
    En fait je voudrais avoir une liste de PluginsParameter quelconques.
    Dans un plugin on doit pouvoir déclarer un PluginsParameter<Interger> et un autre PluginsParameter<Double> , mettre les deux dans la liste ET (c'est là le problème) récupérer leurs valeurs (membre value) par un appel de méthode sur la liste et dans le type d'origine (Integer, Double, ...).

    Plus j'y pense et finalement je me dis que ce doit pas être possible directement ;-(

    En tout cas merci pour les infos et les astuces.

  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
    Ok je n'avais pas vraiment compris ton problème...

    Citation Envoyé par Prodejeu
    Plus j'y pense et finalement je me dis que ce doit pas être possible directement ;-(
    C'est possible en utilisant le wilcard <?> qui authorisera n'importe quel type. Et du coup je comprend mieux ton problème, puisque tu ne peut pas récupérer l'objet dans son type réel mais seulement en tant que Number...

    Tu peux palier à cela en castant avec (T), par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class PluginsParametersList {
        
        private Map<String, PluginsParameter<?>> list = new HashMap<String, PluginsParameter<?>>( );
        
        public <T extends Number & Comparable<T>> T get(String name){
            return (T) list.get(name).getValue();
        }
    
    ...
    Seulement tu as un warning sur le cast, car du coup ton code n'est plus sécurisé car si le type réel ne correspond pas à ce que tu attends tu auras une ClassCastException...

    Tu voudrais a la fois utiliser un code complètement générique mais tout en utilisant un typage fort... Ce n'est pas possible...

    Le mieux serait surement d'utiliser la classe Number. Après tout elle définit toutes les méthodes pour obtenir le type primitifs correspond dans le type voulu :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class PluginsParametersList {
     
        private Map<String, PluginsParameter<?>> list = new HashMap<String, PluginsParameter<?>>( );
     
        public Number get(String name){
            return list.get(name).getValue();
        }
     
    ...
    Et si tu as vraiment besoin d'un type spécifique il te faudra utiliser des instanceof :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Double d = null;
    Number n = ppList.get("name");
    if (n instanceof Double) {
               d = (Double) n;
    }
    a++

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Citation Envoyé par adiGuba
    Tu voudrais a la fois utiliser un code complètement générique mais tout en utilisant un typage fort... Ce n'est pas possible...
    Oui je m'en rend compte, il n'y a pas de solution miracle.
    Au moins ça m'a permis de voir les generics un peu plus en profondeur (autrement qu'avec les ArrayList typés ;-) ).

    Finalement j'ai opté pour ta solution et j'ai rajouté quelques méthodes.
    J'estime que si le concepteur du plugins crée un paramètre int et qu'il cherche à récupérer un double, je ne peux pas grand chose pour lui à part lui filer l'adresse de bon tutos.

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    public class PluginsParametersList{
     
        private Map<String, PluginsParameter<?>> list = new HashMap<String, PluginsParameter<?>>( ); 
     
        public <T extends Number & Comparable<T>> void put(String name, T value, T minimum, T maximum){
            if(list.containsKey(name)){
                list.remove(name);
            }
            list.put(name, new PluginsParameter<T>(name, value, minimum, maximum));
        }
     
        public void remove(String name){
            if(list.containsKey(name)){
                list.remove(name);
            }
        }
     
        public boolean contains(String name){
            return list.containsKey(name);
        }
     
        @SuppressWarnings("unchecked")
        public <T extends Number & Comparable<T>> T get(String name){
            return (T)list.get(name).getValue();
        }
     
        public byte getByte(String name){
        	return list.get(name).getValue().byteValue();
        }
     
        public double getDouble(String name){
        	return list.get(name).getValue().doubleValue();
        }
     
        public float getFloat(String name){
        	return list.get(name).getValue().floatValue();
        }
     
        public int getInteger(String name){
        	return list.get(name).getValue().intValue();
        }
     
        public long getLong(String name){
        	return list.get(name).getValue().longValue();
        }
     
        public short getShort(String name){
        	return list.get(name).getValue().shortValue();
        }
    }
    Avant de venir chercher de l'aide j'avais également essayer de typer ma liste avec des jokers mais j'avais essayé ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Map<String, PluginsParameter2<? extends Number & Comparable<?>>> list = new HashMap<String, PluginsParameter2<? extends Number & Comparable<?>>>( );
    Evidement ca marche pas, mais est-ce complétement absurde ou est-ce qu'il y a une possibilité de typage de ce genre ?

    J'ai également remarqué que le compilo digérait mal le & avec les jokers.

    Merci beaucoup pour ton aide.

  6. #6
    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
    Je te conseillerais juste d'indiquer le risque de ClassCastException dans la définition de ta méthode (et même la javadoc si tu en fait une) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        @SuppressWarnings("unchecked")
        public <T extends Number & Comparable<T>> T get(String name) throws ClassCastException {
            return (T)list.get(name).getValue();
        }

    Citation Envoyé par Prodejeu
    J'ai également remarqué que le compilo digérait mal le & avec les jokers.
    Il me semble surtout que le & ne peut être utilisé que pour la déclaration de classe ou de méthode générique...

    a++

  7. #7
    Candidat au Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Citation Envoyé par adiGuba
    Je te conseillerais juste d'indiquer le risque de ClassCastException dans la définition de ta méthode (et même la javadoc si tu en fait une)
    Ok c'est noté, et oui je vais faire une javadoc.
    On devrait toujours faire une javadoc ne fusse que pour soit, ca évite souvent de se demander pendant un bon moment ce que l'on a voulu faire.

    Encore merci pour les infos.
    A++

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

Discussions similaires

  1. Problème avec les Generics et héritage
    Par jojodu31 dans le forum Langage
    Réponses: 5
    Dernier message: 17/06/2010, 10h04
  2. Problèmes avec les generics
    Par mehdi_swatch dans le forum Langage
    Réponses: 12
    Dernier message: 10/07/2006, 18h35
  3. Problème avec les apostrophes
    Par misterbillyboy dans le forum Requêtes
    Réponses: 2
    Dernier message: 15/07/2003, 16h39
  4. Problème avec les fichiers .JPG
    Par cprogil dans le forum Langage
    Réponses: 5
    Dernier message: 10/06/2003, 15h44
  5. []Problème avec les formulaires Outlook
    Par davidinfo dans le forum Outlook
    Réponses: 6
    Dernier message: 05/12/2002, 09h59

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