J'ai une classe de médicaments génériques, Foo<T>
. Dans une méthode de Foo
, je veux obtenir l'instance de classe de type T
, mais je ne peux tout simplement pas appeler T.class
.
Quelle est la meilleure façon de contourner le problème en utilisant T.class
?
import com.fasterxml.jackson.core.type.TypeReference;
new TypeReference<T>(){}
Réponses:
La réponse courte est qu'il n'y a aucun moyen de découvrir le type d'exécution des paramètres de type générique en Java. Je suggère de lire le chapitre sur l'effacement des types dans le Tutoriel Java pour plus de détails.
Une solution populaire à cela consiste à passer le
Class
paramètre du type au constructeur du type générique, par exemplela source
typeParameterClass
sans une affectation par défaut dans le constructeur est parfaitement bien. Il n'est pas nécessaire de le régler une deuxième fois.Je cherchais un moyen de le faire moi-même sans ajouter de dépendance supplémentaire au chemin de classe. Après quelques recherches , je trouve qu'il est possible aussi longtemps que vous avez un générique supertype. C'était OK pour moi car je travaillais avec un DAO couche avec un super-type de couche générique. Si cela correspond à votre scénario, c'est l'approche la plus soignée à mon humble avis.
La plupart des cas d'utilisation génériques que j'ai rencontrés ont une sorte de supertype générique, par exemple
List<T>
pourArrayList<T>
ouGenericDAO<T>
pourDAO<T>
, etc.Solution Java pure
L'article Accès aux types génériques lors de l'exécution en Java explique comment vous pouvez le faire en utilisant du Java pur.
Solution de printemps
Mon projet utilisait Spring, ce qui est encore mieux car Spring a une méthode utilitaire pratique pour trouver le type. C'est la meilleure approche pour moi car elle semble la plus soignée. Je suppose que si vous n'utilisiez pas Spring, vous pourriez écrire votre propre méthode utilitaire.
la source
Il y a cependant une petite faille: si vous définissez votre
Foo
classe comme abstraite. Cela signifie que vous devez instancier votre classe en tant que:(Notez les accolades doubles à la fin.)
Vous pouvez maintenant récupérer le type de
T
lors de l'exécution:Notez cependant que cela
mySuperclass
doit être la superclasse de la définition de classe définissant réellement le type final pourT
.Il n'est pas non plus très élégant, mais vous devez décider si vous préférez
new Foo<MyType>(){}
ounew Foo<MyType>(MyType.class);
dans votre code.Par exemple:
Alors:
la source
TypeLiteral
a
etb
créé cette façon à la fois étendre la même classe , mais pas les classes d'instance identiques.a.getClass() != b.getClass()
Une approche / solution / solution standard consiste à ajouter un
class
objet au (x) constructeur (s), comme:la source
Imaginez que vous ayez une superclasse abstraite générique:
Et puis vous avez une deuxième classe qui étend Foo avec une barre générique qui étend T:
Vous pouvez obtenir la classe
Bar.class
dans la classe Foo en sélectionnant laType
(à partir de la réponse de bert bruynooghe) et en la déduisant en utilisantClass
instance:Vous devez noter que cette opération n'est pas idéale, c'est donc une bonne idée de mettre en cache la valeur calculée pour éviter plusieurs calculs à ce sujet. L'une des utilisations typiques est dans l'implémentation DAO générique.
L'implémentation finale:
La valeur renvoyée est Bar.class lorsqu'elle est invoquée à partir de la classe Foo dans une autre fonction ou de la classe Bar.
la source
toString().split(" ")[1]
c'était le problème, évitez les"class "
Voici une solution de travail:
REMARQUES: ne peut être utilisé qu'en superclasse
Child extends Generic<Integer>
)OU
new Generic<Integer>() {};
)la source
Vous ne pouvez pas le faire à cause de l'effacement du type. Voir aussi Stack Overflow question génériques Java - effacement de type - quand et ce qui se passe .
la source
Une meilleure route que la classe suggérée par les autres est de passer un objet qui peut faire ce que vous auriez fait avec la classe, par exemple, créer une nouvelle instance.
la source
J'ai eu ce problème dans une classe générique abstraite. Dans ce cas particulier, la solution est plus simple:
et plus tard sur la classe dérivée:
la source
J'ai une solution (laide mais efficace) pour ce problème, que j'ai utilisée récemment:
la source
C'est possible:
Vous avez besoin de deux fonctions de hibernate-generic-dao / blob / master / dao / src / main / java / com / googlecode / genericdao / dao / DAOUtil.java .
Pour plus d'explications, voir Refléter les génériques .
la source
J'ai trouvé un moyen générique et simple de le faire. Dans ma classe, j'ai créé une méthode qui renvoie le type générique en fonction de sa position dans la définition de classe. Supposons une définition de classe comme celle-ci:
Créons maintenant quelques attributs pour conserver les types:
Vous pouvez ensuite créer une méthode générique qui renvoie le type en fonction de l'index de la définition générique:
Enfin, dans le constructeur, il suffit d'appeler la méthode et d'envoyer l'index pour chaque type. Le code complet devrait ressembler à:
la source
Comme expliqué dans d'autres réponses, pour utiliser ce
ParameterizedType
approche, vous devez étendre la classe, mais cela semble être un travail supplémentaire pour créer une toute nouvelle classe qui l'étend ...Ainsi, rendre la classe abstraite vous oblige à l'étendre, satisfaisant ainsi l'exigence de sous-classement. (en utilisant @Getter de lombok).
Maintenant, pour l'étendre sans définir de nouvelle classe. (Notez le {} à la fin ... étendu, mais n'écrasez rien - sauf si vous le souhaitez).
la source
Je suppose que, puisque vous avez une classe générique, vous auriez une variable comme ça:
(cette variable doit prendre une valeur chez le constructeur)
Dans ce cas, vous pouvez simplement créer la méthode suivante:
J'espère que cela aide!
la source
la source
Si vous étendez ou implémentez une classe / interface utilisant des génériques, vous pouvez obtenir le type générique de classe / interface parent, sans modifier aucune classe / interface existante.
Il pourrait y avoir trois possibilités,
Cas 1 Lorsque votre classe étend une classe qui utilise des génériques
Cas 2 Lorsque votre classe implémente une interface qui utilise des génériques
Cas 3 Lorsque votre interface étend une interface qui utilise des génériques
la source
C'est assez simple. Si vous avez besoin de la même classe:
la source
En fait, je suppose que vous avez un champ dans votre classe de type T. S'il n'y a pas de champ de type T, quel est l'intérêt d'avoir un type générique? Donc, vous pouvez simplement faire une instance de ce champ.
Dans mon cas, j'ai un
dans ma classe, et je vérifie si le type de classe est "Localité" parBien sûr, cela ne fonctionne que si le nombre total de classes possibles est limité.
la source
Cette question est ancienne, mais maintenant le mieux est d'utiliser Google
Gson
.Un exemple pour devenir personnalisé
viewModel
.Classe de type générique
la source
Je voulais passer T.class à une méthode qui utilise des génériques
La méthode readFile lit un fichier .csv spécifié par fileName avec fullpath. Il peut y avoir des fichiers csv avec des contenus différents, donc je dois passer la classe de fichier modèle afin que je puisse obtenir les objets appropriés. Puisque c'est la lecture du fichier csv, je voulais le faire de manière générique. Pour une raison ou une autre, aucune des solutions ci-dessus n'a fonctionné pour moi. Je dois utiliser
Class<? extends T> type
pour le faire fonctionner. J'utilise la bibliothèque opencsv pour analyser les fichiers CSV.C'est ainsi que la méthode readFile est appelée
la source
J'utilise une solution de contournement pour cela:
la source