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

Java Discussion :

Probleme Generics en java


Sujet :

Java

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Août 2007
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 200
    Points : 67
    Points
    67
    Par défaut Probleme Generics en java
    Bonjour j'ai l'impression de ne pas avoir bien compris les Generics en java. En effet, quand j'ai vu une classe dont la signature est la suivante:

    public class CardMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
    Et quand je l'imite en me créant la classe suivante:

    public class Etudiant <String,String,Integer>{
    j'ai l'erreur
    Duplicate type parameter String
    L'erreur est sur le deuxieme String (me disant que je n'ai pas le droit de le mettre 2 fois). Alors comment ca se fait que ca marche pour la classe CardMapper (avec Text)?

    D'avance merci.

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    La différence entre ton code et le code dont tu t'inspires se situe ici :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public class CardMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
    Il faut distinguer 2 cas :

    • Le paramétrage d'une classe
    • le typage ou valuation d'un paramètre de classe


    Lorsqu'on écrit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    public class Etudiant <String,String,Integer> {
    }
    On dit : je déclare une classe appelée Etudiant paramétrée par 3 paramètres appelé String, String et Integer. Ici, ce ne sont pas les noms de classes. Tu aurais pu écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    public class Etudiant <X,X,Y> {
    }
    Et, évidemment, si 2 paramètres ont le même nom, Java ne pourrait faire la différence (comme avec 2 variables dans le même scope), et donc te dit que tu as 2 paramètres avec le même nom.

    Par ailleurs, il vaut mieux ne pas utiliser de nom de classes comme noms de paramètres, parce que tu ne pourras plus utiliser ces classes dans la classe (parce que Java pensera que tu références le paramètre et non la classe). D'ailleurs, ton IDE te signalera un warning à ce sujet (le paramètre String cache le type String, par exemple).

    Quand on écrit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public class CardMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
    C'est qu'on a déclaré la classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    public class Mapper<W, T, U, I> { // j'ai pris des noms de paramètres au pif
    }
    et donc on crée une version spécifique de Mapper par extension, en disant que :
    • W est LongWritable
    • T est Text
    • U est Text
    • I est IntWritable



    Exemple pratique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Exemple<T> {
     
         private T value;
     
         public void setValue(T value) {
              this.value=value;
         }
     
         public T getValue() {
              return this.value;
         }
     
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    public class StringExemple extends Exemple<String>  {
    }
    Ce qui permet de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class Test {
       public static void main(String[] args) {
     
             StringExemple s1 = new StringExemple();
             s1.setValue("toto");
     
             Exemple<Integer> i1 = new Exemple<>();
             i1.setValue(42);
     
       }
    }
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Août 2007
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 200
    Points : 67
    Points
    67
    Par défaut
    Merci beaucoup joel.drigo pour ces explications claires et détaillées. Je comprends mieux les Generics.La seule partie que je n'ai pas bien compris c'est dans le 1er cas quand tu me dis:
    Par ailleurs, il vaut mieux ne pas utiliser de nom de classes comme noms de paramètres, parce que tu ne pourras plus utiliser ces classes dans la classe (parce que Java pensera que tu références le paramètre et non la classe). D'ailleurs, ton IDE te signalera un warning à ce sujet (le paramètre String cache le type String, par exemple).
    Par là veux-tu dire ne pas utiliser les classes java prédéfinis tels que String,Integer,.. (et utiliser par exemple plutôt String1, Integer1 etc...)? Si tel est le cas je le comprend bien. C'est logique. Peux-tu me confirmer stp?

    Derniere question: pour paramétrer une classe, c'est quoi la recommandation: mettre des lettre en majuscule (genre MaClasse<A,B,C,D> par exemple au lieu de MaClasse<Param1,Param2,Param3,Param4> ?

    Encore merci....

  4. #4
    Membre chevronné
    Avatar de eulbobo
    Homme Profil pro
    Développeur Java
    Inscrit en
    Novembre 2003
    Messages
    786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Points : 1 993
    Points
    1 993
    Par défaut
    Quand tu définis un type générique, il vaut mieux faire en sorte qu'il ne correspondent à RIEN qui pourrait passer pour un nom de variable ou un nom de classe.

    C'est pour ça qu'on utilise une lettre majuscule seule.
    Il existe des normes pour définir quelle lettre mettre :

    E - pour un Element (très utilisé dans les collections ou les wrappers)
    K - pour Key : une clé
    N - pour Number : un nombre
    T - pour Type, ça définit un type de classe
    V - pour Value, une valeur
    S,U,V etc. - si tu as plusieurs types différents

    A toi de voir si tu définis MaClasse<A, B, C, D> ou MaClasse<E, K, U, S>


    Exemple : dans l'API, une Map est définie comme Map<K, V> : soit une map clé/valeur
    Une liste est définie comme List<E> : une liste d'éléments

    Et n'oublie pas que dans tes déclaration, tu peux forcer certains points...

    MaClasse<V extends Number> : tu ne pourras pas instancier de classe dans laquelle le générique n'est pas un Number.
    Quelques exemples:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    // quelques exemples qui marchent
    MaClasse<Long> maclasse = new MaClasse<Long>(); // ca marche
    MaClasse<Number> maclasse = new MaClasse<Number>(); // ca marche
    MaClasse<Integer> maclasse = new MaClasse<>(); // ca marche et c'est plus court à écrire
     
    // quelques exemples qui ne compilent pas !
    MaClasse<Long> maclasse = new MaClasse<Number>(); // CA NE MARCHE PAS, il faut définir le même type des deux côtés
    MaClasse<String> maclasse = new MaClasse<String>(); // CA NE MARCHE PAS, String n'étend pas Number
    Je ne suis pas mort, j'ai du travail !

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Août 2007
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 200
    Points : 67
    Points
    67
    Par défaut
    Merci bcp eulbobo. C'est vraiment clair! ta reponse et celle de joel.drigo m'aident vraiment.
    Mais quand tu dis :
    Et n'oublie pas que dans tes déclaration, tu peux forcer certains points...
    qu'entends tu par ca?

    Derniere question: supposons que dans la classe que je veux paramétrer, je veuille utiliser:
    - 2 elements
    - 3 types (3 classes)
    - 1 nombre
    Sachant que je ne peux pas faire MaClasse <E,E,T,T,T,N) alors c'est quoi la recommandation?

  6. #6
    Membre chevronné
    Avatar de eulbobo
    Homme Profil pro
    Développeur Java
    Inscrit en
    Novembre 2003
    Messages
    786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Points : 1 993
    Points
    1 993
    Par défaut
    Je voulais dire ça
    Et n'oublie pas que dans tes déclaration, tu peux forcer certains points...
    MaClasse<V extends Number> : tu ne pourras pas instancier de classe dans laquelle le générique n'est pas un Number.
    Bref, faire en sorte de ne pas accepter n'importe quel type de classe générique :p


    Derniere question: supposons que dans la classe que je veux paramétrer, je veuille utiliser:
    - 2 elements
    - 3 types (3 classes)
    - 1 nombre
    Sachant que je ne peux pas faire MaClasse <E,E,T,T,T,N) alors c'est quoi la recommandation?
    Question :
    - les deux éléments, ils sont de type/classe différents? Ils ont une interface en commun?
    - Les trois types (classes) : même question : 3 types/classes différentes? Dans une même hiérarchie? D'une même interface?
    - Un nombre... Ben la j'aurai envie de dire que tu mets directement Number...

    De toute façon, si toutes tes classes/types/éléments sont différents, tu ne pourras pas déclarer MaClasse<E, E, T, T, T, N> vu que tu ne peux pas déclarer deux fois le même type.

    Je te donne un exemple de comment venir aux génériques :
    L'idée, c'est de dire "J'ai une classe dans laquelle je peux manipuler des trucs et des bidules"
    Tu commences donc par décrire ta classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public class TrucsEtBidules{
         public Object truc;
         public Object bidule;
    }
    Mais ça sert pas à grand chose et tu aimerais bien pouvoir avoir accès à plus de choses
    Donc tu mets un générique
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public class TrucsEtBidules<T>{
         public T truc;
         public T bidule;
    }
    Du coup, ensuite, tu peux l'utiliser comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    TrucsEtBidule<String> mesTrucs = new TrucsEtBidules<String>;
    mesTrucs.truc = "toto";
    mesTrucs.bidule = "titi";
     
    TrucsEtBidule<Long> mesTrucs2 = new TrucsEtBidules<Long>;
    mesTrucs2.truc = 2L;
    mesTrucs2.bidule = 8L;
    Et tu manipules directement des éléments dont tu as précisé le type.

    Ensuite, tu veux pouvoir avoir deux types différents pour truc et bidule
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public class TrucsEtBidules<T, U>{
         public T truc;
         public U bidule;
    }
    Du coup, la déclaration change :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    TrucsEtBidule<String, String> mesTrucs = new TrucsEtBidules<String, String>;
    mesTrucs.truc = "toto";
    mesTrucs.bidule = "titi";
     
    TrucsEtBidule<Long, String> mesTrucs2 = new TrucsEtBidules<Long, String>;
    mesTrucs2.truc = 2L;
    mesTrucs2.bidule = "c'est un bidule";
    Et finalement, tu veux limiter les possibilités de manipulation des objets à certains types précis... et donc faire plus de choses avec !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    public class TrucsEtBidules<T extends Collection, U extends Number>{
         public T truc;
         public U bidule;
     
         public Number getUValue(){
               return bidule; // on sait que c'est un number
         }
     
         public int getTrucSizeValue(){
               return truc.size(); // on sait que c'est une collection
         }
    }
    Tu vois? (et ce n'est que le début :p)
    Je ne suis pas mort, j'ai du travail !

  7. #7
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par mafanta Voir le message
    Merci bcp eulbobo. C'est vraiment clair! ta reponse et celle de joel.drigo m'aident vraiment.
    Mais quand tu dis :

    qu'entends tu par ca?
    @eulbobo veut probablement parler de contraintes qu'on peut ajouter dans la déclaration du paramètre.

    Par exemple, si tu reprends mon exemple, on peut écrire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    public class NumberExemple<T extends Number> extends Exemple<T>  {
    }
    On indique ici qu'on contraint le type paramétré à étendre Number. Ainsi on pourra faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    public class IntegerExemple extends NumberExemple<Integer> {
    }
    Mais pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    public class StringExemple2 extends NumberExemple<String> {
    }
    Ceci permet de mettre dans notre classe (NumberExemple) des méthodes qui ne fonctionne que pour la contrainte. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public class NumberExemple<T extends Number> extends Exemple<T>  {
     
             public int intValue() {
                 return getValue().intValue(); // cette méthode existe sur la classe Number
             }
     
    }
    (Il y a d'autre types de contraintes, comme il y a d'autres contextes d'utilisation des types génériques dont on pas parlé)

    Citation Envoyé par mafanta Voir le message

    Derniere question: supposons que dans la classe que je veux paramétrer, je veuille utiliser:
    - 2 elements
    - 3 types (3 classes)
    - 1 nombre
    Sachant que je ne peux pas faire MaClasse <E,E,T,T,T,N) alors c'est quoi la recommandation?
    Déjà, je pense qu'il faut éviter d'avoir trop de paramètres, ça complique quand même la lecture, et l'utilisation. Ça veut souvent dire que la classe fait trop de chose et pourrait être découpée en classes plus dédiées.

    Ensuite, pour ma part, lorsqu'il y a multiplication des paramètres, j'ai tendance à passer outre la convention, et à utiliser :

    1. Pour les cas simples, j'utilise la convention (souvent en utilisant T ou P (ou K et V, pour de la Map)...)
    2. Tout d'abord des lettres en rapport avec le type (lorsqu'il y a contrainte), ou l'objet du paramètre (par exemple, si c'est une valeur V, un paramètre P, un composant swing C, etc...)
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      AbstractSingleAssignWizard<A extends IAffectable,T extends AbstractSingleAssignWizardParam<A>> extends AbstractAssignWizard<A, T> {
      A comme Affectable et T comme Type
      Ou pour reprendre un Exemple Java :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      public interface Collector<T, A, R>
      • T : type
      • A : accumulator
      • R : result


    3. Lorsque les paramètres se multiplie, je vais utiliser des noms plus long et signification
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      public abstract class AbstractWizard<ACTION extends Action, PARAMETERS extends WizardParameterList<?>> {
       
      }


    Le but c'est qu'on ne se paume pas, et qu'on comprenne à quoi servent les paramètres...
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Août 2007
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 200
    Points : 67
    Points
    67
    Par défaut
    Merci beaucoup à vous deux pour ces explications. Maintenant je vais pouvoir me mettre aux generics qui me faisaient peur auparavant!!

    Encore merci.

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

Discussions similaires

  1. probleme tri en java
    Par kloe dans le forum Collection et Stream
    Réponses: 3
    Dernier message: 18/10/2006, 23h01
  2. [REDHAT] Probleme avec la java RE
    Par blackstreet dans le forum RedHat / CentOS / Fedora
    Réponses: 9
    Dernier message: 15/06/2006, 10h22
  3. Probleme d'exception : java.net.UnknownHostException
    Par kedare dans le forum Entrée/Sortie
    Réponses: 1
    Dernier message: 08/06/2006, 20h59
  4. Probleme SQL prepareStatement JAVA
    Par grizzz dans le forum Langage SQL
    Réponses: 12
    Dernier message: 05/08/2005, 11h29
  5. Problème d'installation java
    Par mickey hollywood dans le forum Applications et environnements graphiques
    Réponses: 6
    Dernier message: 23/03/2005, 11h01

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