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 :

Utiliser une Class en tant que type générique


Sujet :

Langage Java

  1. #1
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut Utiliser une Class en tant que type générique
    Bonjour,

    J'ai une classe avec type générique (Params1). Je voudrais lui passer un objet Class (récupéré via reflexion), comme dans FromClass et FromClass2 ci-dessous.
    Java ne compile pas les FromClass et FromClass2.
    Comment puis-je transformer "new Integer(1).class" en "Integer", ou "Class.forName("java.util.List")" en "List" ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public class Params1<T> {}
    public class Classic extends Params1<Integer> {}
    public class FromClass extends Params1<new Integer(1).class> {}
    public class FromClass2 extends Params1<Class.forName("java.util.List")> {}
    Merci d'avance.

  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,

    Déjà c'est Integer.class ou new Integer(1).getClass();. Et puis ça ce sont des instructions, destinées à être exécutées au runtime. Ce qu'on met entre < et >, c'est du source, de la syntaxe.

    c'est bien tout simplement comme ça que tu dois faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public class Classic extends Params1<Integer> {}
    Et ce que tu va récupérer par réflexion, c'est également au runtime, donc je ne vois pas ce que tu en ferais dans les déclarations de classe ?

    Est-ce que ce que tu voudrais pouvoir faire quelque chose comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Class<?> nomDeClass = methodeQuiDetermineUneClassParReflexion(...);
     
    FromClass<... quelque chose qui correspond à nomDeClass> instance = new FromClass<>();
    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 éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    Bonjour Joel, et merci pour ces précisions.
    Oui, c'est exactement ce que je veux faire !

    Cela dit, les classes que je détermine par réflexion au runtime sont des types génériques fournis "en dur" à des classes paramétrées, et donc pourraient être déterminées à la compilation (mais je ne sais pas comment).

  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
    Mais ça servirait à quoi de préciser le type au runtime ? On ne déclare pas les classes au runtime, mais dans les sources. Si T est quelconques, tu ne peux pas taper du code spécifique dans le source (appeler des méthodes spécifique d'une classe inconnue représentée par T).

    Si le but est de générer dynamiquement des classes, tu passeras par des sources (que tu compileras par javac à la volée), donc des String (ou des fichiers), donc tu peux patcher ton source directement avec le nom de la classe (classe.getName()).

    Citation Envoyé par shaiHulud Voir le message
    Cela dit, les classes que je détermine par réflexion au runtime sont des types génériques fournis "en dur" à des classes paramétrées, et donc pourraient être déterminées à la compilation .
    Je ne suis pas sûr de comprendre cette phrase. La classe déterminée par réflexion provient d'où ? D'un Field, d'un paramètre de méthode, de quoi ? Qu'entends-tu par "en dur" ? Pourquoi a-t-on besoin de réflexion ? Qu'est-ce que tu essayes de faire au juste ?
    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
    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
    Pour le dire autrement, arrêtons là la théorie, les mots, les idées abstraites.

    Du code. Celui qu'on a, celui qu'on veut avoir.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    oui oui, ca arrive

    J'ai une classe paramétrée A, avec un méthode attendant un argument d'une autre classe B ayant le même paramètre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public class B<T> {}
    public class A<T> {
        public void foo(B<T> arg)  {}
    }
    Je veux mocker l'argument arg en lui passant une instance d'une classe dérivée C de même paramètre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public class C<T> extends B<T> {}
    C<Integer> mockedArgument = new C<>();
    A<Integer> a = new A<>();
    a.foo(mockedArgument);
    Jusque la pas de problème.

    Ce que je voudrais, c'est éviter d'avoir à préciser moi-même le type générique de C, mais plutôt le déduire de celui de A.
    La raison est que j'ai déja à disposition du code utilisant A et B, avec plusieurs type T sous-jacent, et que j'aimerais avoir un mocking générique qui évite d'avoir à repréciser <T> au cas par cas.

    Donc je récupère au runtime le type <T> de A via reflexion (enfin la classe et non le type - c'est tout mon problème):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Class genericParameter = (Class) ((ParameterizedType) A.class.getGenericSuperclass()).getActualTypeArguments()[0];
    Et j'essaie ensuite de créer C avec cette information, et c'est la ou je bloque.

    Les remarques de Joel indiquent que c'est trop tard (le runtime) pour y arriver. Ce que ma phrase laconique signifie, c'est que j'accède à cette information au runtime (reflexion), mais que cette information est a priori disponible au moment de la compilation.
    J'ai croisé des construction ou le type et la classe étaient passés en argument générique, est-ce une bonne approche ?
    Sinon, j'imagine que je pourrai définir C interne à une classe MockedA (pour récupérer les bons génériques), et réaliser le mocking en changeant new A() par new MockedA() - mais c'est justement ce style intrusif (modifiant un code déja existant) que j'essaye d'éviter.

  7. #7
    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
    Solution purement genérique

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public B<T> buildMockB(A<T> a){
        return new C<T>();
    }
     
    A<Integer> a = new A<>();
    B<Integer> mockB = buildMockB(a);
    a.foo(mockB);
    Si tu ne connais pas du tout integer à la compilation, par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    A<?> a  = ....;
    B<??????> mockB = buildMockB(a);
    a.foo(mockB);
    ca va évidement foirer. Dans ce cas je vois deux possibilités:

    1) Mentir délbérément au compilateur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    A<Object> a  = (A<Object>)....;
    B<Object> mockB = buildMockB(a);
    a.foo(mockB);
    Il va te mettre un warning disant que le typecast n'est pas vérifiable, mais ça passera

    2) Evincer les generiques:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    A a  = ....;
    B mockB = buildMockB(a);
    a.foo(mockB);
    Il va te mettre un warning disant que sans type déclaré, il peux pas vérifier que ça passera

    Tu peux aussi simplifier le problème en enrobant dans une méthode qui va fixer le type du point de vu du compilateur. Exemple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public <T> void aFoo(A<T> a){
      B<T> mockB = new C<T>();
      a.foo(mockB);
    }
    A<?> a = ....
    aFoo(a);

Discussions similaires

  1. Android Studio utiliser une classe en tant que bibliothèque
    Par ChPr dans le forum Android Studio
    Réponses: 0
    Dernier message: 17/11/2015, 23h06
  2. Implémenter une classe en tant que source de données
    Par BasicZX81 dans le forum VB.NET
    Réponses: 3
    Dernier message: 06/10/2013, 14h42
  3. Réponses: 2
    Dernier message: 24/08/2006, 17h48
  4. Réponses: 2
    Dernier message: 05/08/2006, 13h29
  5. utilisation d"une variable en tant que motif de
    Par bilout dans le forum Langage
    Réponses: 4
    Dernier message: 26/03/2006, 20h19

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