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 :

Comment connaitre la classe d'un type paramétré d'un générique ?


Sujet :

Langage Java

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    75
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 75
    Points : 54
    Points
    54
    Par défaut Comment connaitre la classe d'un type paramétré d'un générique ?
    Bonsoir,

    J'ai les classes suivantes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public class Classe0 {}
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public class Classe1 {}
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public class Classe0Impl extends Class0 {}
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public class Classe1Impl extends Class1 {}
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public class Generic<A extends Classe0, B extends Classe1> {
    	public void displayBClass() {
    		// TODO
    	}
    }
    Je souhaite que la méthode displayBClass() affiche la classe de B, c'est à dire Classe1Impl.
    Si j'écris :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    	public void displayBClass() {
    		TypeVariable<?>[] generics = this.getClass().getTypeParameters();
    		System.out.println(generics[1].getBounds());
     
    	}
    j'obtiens "Class1" mais je souhaiterais obtenir "Classe1Impl".
    Comment faire ?

  2. #2
    Membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    75
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 75
    Points : 54
    Points
    54
    Par défaut
    En fait, le but inavouable est de créer une instance de B, faire un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Classe1 classe1 = new Classe1Impl();
    via la technique du
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	B createContents(Class<B> clazz) throws InstantiationException, IllegalAccessException {
    		return clazz.newInstance();
    	}
    mais j'ai besoin de connaître la classe de B, c'est à dire Classe1Impl.

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

    Citation Envoyé par sql_ignorant Voir le message
    Comment connaitre la classe d'un type paramétré d'un générique ?
    C'est impossible : les types des paramètres n'existent pas au runtime. Les types paramétrés ne sont utilisés qu'à la compilation.
    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.

  4. #4
    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 sql_ignorant Voir le message
    En fait, le but inavouable est de créer une instance de B, faire un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Classe1 classe1 = new Classe1Impl();
    via la technique du
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	B createContents(Class<B> clazz) throws InstantiationException, IllegalAccessException {
    		return clazz.newInstance();
    	}
    mais j'ai besoin de connaître la classe de B, c'est à dire Classe1Impl.
    C'est plutôt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	B createContents(Class<B> clazz) throws InstantiationException, IllegalAccessException {
    		return (B)clazz.newInstance();
    	}

    Si tu appelles :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Classe0 var = factory.createContents(Classe0.class);
    ça créé bien un Classe0 (en supposant que B a bien été paramétré en Classe0 pour l'instance référencé par factory, et qu'il y a bien un constructeur sans paramètre pour Classe0 évidemment).
    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.

  5. #5
    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 joel.drigo Voir le message
    C'est plutôt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	B createContents(Class<B> clazz) throws InstantiationException, IllegalAccessException {
    		return (B)clazz.newInstance();
    	}
    Le cast est inutile : newInstance() de Class<B> renvoi déjà un élément de type B...



    @sql_ignorant : les types paramétrées ne sont pas connu à l'exécution (sauf en cas d'un héritage typé, mais c'est un cas particulier).
    La solution consiste simplement à spécifier la classe en paramètre du constructeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public static class Generic<A extends Classe0, B extends Classe1> {
     
    	private final Class<A> clazzA;
    	private final Class<B> clazzB;
     
    	public Generic(Class<A> clazzA, Class<B> clazzB) {
    		this.clazzA = Objects.requireNonNull(clazzA);
    		this.clazzB = Objects.requireNonNull(clazzB);
    	}
     
    	public void displayBClass() {
    		// TODO
    	}
    }

    a++

  6. #6
    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 adiGuba Voir le message
    Le cast est inutile : newInstance() de Class<B> renvoi déjà un élément de type B...
    Il me semblait qu'il fallait, probablement une confusion de ma part avec un autre cas.
    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.

  7. #7
    Modérateur
    Avatar de Gugelhupf
    Homme Profil pro
    Analyste Programmeur
    Inscrit en
    Décembre 2011
    Messages
    1 320
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Analyste Programmeur

    Informations forums :
    Inscription : Décembre 2011
    Messages : 1 320
    Points : 3 741
    Points
    3 741
    Billets dans le blog
    12
    Par défaut
    @sql_ignorant : Comment connaitre la classe d'un type paramétré d'un générique ?
    Citation Envoyé par joel.drigo Voir le message
    C'est impossible : les types des paramètres n'existent pas au runtime. Les types paramétrés ne sont utilisés qu'à la compilation.
    C'est possible, on se sert de la classe ParametrizedType, tu peux avoir un aperçu de son utilisation dans la méthode fillField() mon dans mon API html-form (on récupère le type T de List<T>). Si tu veux savoir comment utiliser l'API html-form tu peux jeter un coup d'oeil ici.
    N'hésitez pas à consulter la FAQ Java, lire les cours et tutoriels Java, et à poser vos questions sur les forums d'entraide Java

    Ma page Developpez | Mon profil Linkedin | Vous souhaitez me contacter ? Contacter Gokan EKINCI

  8. #8
    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 Gugelhupf Voir le message
    C'est possible, on se sert de la classe ParametrizedType, tu peux avoir un aperçu de son utilisation dans la méthode fillField() mon dans mon API html-form (on récupère le type T de List<T>). Si tu veux savoir comment utiliser l'API html-form tu peux jeter un coup d'oeil ici.
    On parlait de récupérer la classe d'un paramètre d'une classe dans une instance (méthode display qui affiche le type de A ou B), pas le type paramétré d'un type de field. C'est parce que dans ce cas la déclaration est stockée, y compris la valeur du paramètre. On peut également le faire d'ailleurs sur les types des arguments d'une méthode (ou le type de retour) et également sur des classes filles (parce que le paramètre du type étendu dans la déclaration est stocké) : sauf que contrairement au cas que tu cites, on ne récupères pas une instance de Class, mais de Type, dont on peut récupérer au mieux un nom de classe (un String). On peut faire un Class.forName sauf si le type lui-même est paramétré ! D'ailleurs à ce propos ta méthode fillField fait un ClassCastException si le type du field est paramétré (genre List<List<Integer>>, ou même List<ArrayList<Integer>), parce que le type n'est pas Class<?> mais du ParametrizedType<?>.

    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
    public class UneClasse<T> {
     
     
    	public UneClasse() {
    	}
     
    	public static void main(String[] args) {
     
     
    		ClasseFille1 instance = new ClasseFille1();
     
    		System.out.println(((ParameterizedType)instance.getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName());
     
    		ClasseFille2<Integer> instance2 = new ClasseFille2<>();
     
    		System.out.println(((ParameterizedType)instance2.getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName());
     
     
    	}
     
    	public static class ClasseFille1 extends UneClasse<Integer> {
     
    	}
     
    	public static class ClasseFille2<T extends Number> extends UneClasse<T> {
     
    	}
     
    }
    Le premier println() affiche effectivement java.lang.Integer, mais le second affiche T (on stocke donc bien ce qui est entre <> dans la classe parente indiquée après extends... Mais on ne peut pas obtenir le nom du type du paramètre, soit java.lang.Integer dans le cas de classe ClasseFille2.
    A l'intérieur comme à l'extérieur.

    Il y a aussi cette bidouille avec une classe anonyme :

    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
    public class Exemple<T> {
        final Type type;
     
        protected Exemple() {
            final Type superClass = getClass().getGenericSuperclass();
            type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
        }
     
        public Type getType() { 
        	return type; 
        }
     
        public static void main(String[] args) {
     
        	Exemple<Integer> exemple = new Exemple<Integer>() {
     
        	};
        	System.out.println(exemple.getType()); // affiche java;Lang.Integer
     
        }
     
    }
    Mais bon, n'est-ce-pas aussi simple de passer la classe en argument, comme c'est fait dans des classes comme EnumSet par exemple ?
    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.

  9. #9
    Modérateur
    Avatar de Gugelhupf
    Homme Profil pro
    Analyste Programmeur
    Inscrit en
    Décembre 2011
    Messages
    1 320
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Analyste Programmeur

    Informations forums :
    Inscription : Décembre 2011
    Messages : 1 320
    Points : 3 741
    Points
    3 741
    Billets dans le blog
    12
    Par défaut
    Je suis allé un peu vite dans le lecture, je n'ai pas regardé en détail les exemples donnés (comme d'hab ). Oui passer un Class<T> en paramètre de méthode est toujours une solution qui fonctionne.
    N'hésitez pas à consulter la FAQ Java, lire les cours et tutoriels Java, et à poser vos questions sur les forums d'entraide Java

    Ma page Developpez | Mon profil Linkedin | Vous souhaitez me contacter ? Contacter Gokan EKINCI

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    75
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 75
    Points : 54
    Points
    54
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    @sql_ignorant : les types paramétrées ne sont pas connu à l'exécution (sauf en cas d'un héritage typé, mais c'est un cas particulier).
    La solution consiste simplement à spécifier la classe en paramètre du constructeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public static class Generic<A extends Classe0, B extends Classe1> {
     
    	private final Class<A> clazzA;
    	private final Class<B> clazzB;
     
    	public Generic(Class<A> clazzA, Class<B> clazzB) {
    		this.clazzA = Objects.requireNonNull(clazzA);
    		this.clazzB = Objects.requireNonNull(clazzB);
    	}
     
    	public void displayBClass() {
    		// TODO
    	}
    }

    a++
    C'est justement ce que je voulais éviter...
    Tant pis pour moi, je vais voir si j’arrive à me dépatouiller ainsi et sinon je changerai la conception de mon petit programme.
    Comme aurait dit le plus grand des Enfoirés, il ne me reste que Lisieux pour pleurer

    Merci à vous tous

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 25/06/2009, 10h25
  2. Retrouver le type de class depuis uun type paramétré
    Par Asterius dans le forum Langage
    Réponses: 5
    Dernier message: 04/09/2008, 19h25
  3. Réponses: 2
    Dernier message: 29/11/2006, 10h52
  4. Comment connaitre le type d'un attribut dans une table?
    Par Abdou_9002 dans le forum Bases de données
    Réponses: 1
    Dernier message: 02/03/2006, 10h07

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