J'ai vu des questions similaires mais elles n'ont pas beaucoup aidé.
Par exemple, j'ai cette classe générique:
public class ContainerTest<T>
{
public void doSomething()
{
//I want here to determinate the Class of the type argument (In this case String)
}
}
et une autre classe qui utilise cette classe de conteneur
public class TestCase
{
private ContainerTest<String> containerTest;
public void someMethod()
{
containerTest.doSomething();
}
}
Est-il possible de déterminer la classe du type argument dans la méthode doSomething () sans ayant un type explicite variable/champ ou n'importe quel constructeur dans la classe ContainerTest?
Mise à jour: format modifié de la classe ContainerTest
Le seul moyen est de stocker la classe dans une variable d'instance et de l'exiger en tant qu'argument du constructeur:
public class ContainerTest<T>
{
private Class<T> tClass;
public ContainerTest(Class<T> tClass) {
this.tCLass = tClass;
}
public void doSomething()
{
//access tClass here
}
}
Si vous êtes intéressé par la méthode réflexion, j'ai trouvé une solution partielle dans cet article: http://www.artima.com/weblogs/viewpost.jsp?thread=208860
En bref, vous pouvez utiliser les méthodes Java.lang.Class.getGenericSuperclass()
et Java.lang.reflect.ParameterizedType.getActualTypeArguments()
, mais vous devez sous-classer une super classe parent.
L'extrait suivant fonctionne pour une classe qui directement étend la super-classe AbstractUserType
. Voir l'article référencé pour une solution plus générale.
import Java.lang.reflect.ParameterizedType;
public class AbstractUserType<T> {
public Class<T> returnedClass() {
ParameterizedType parameterizedType = (ParameterizedType) getClass()
.getGenericSuperclass();
@SuppressWarnings("unchecked")
Class<T> ret = (Class<T>) parameterizedType.getActualTypeArguments()[0];
return ret;
}
public static void main(String[] args) {
AbstractUserType<String> myVar = new AbstractUserType<String>() {};
System.err.println(myVar.returnedClass());
}
}
Il n’existe pas de moyen "propre" d’obtenir l’argument Type générique dans la classe . Au lieu de cela, un modèle courant consiste à transmettre la classe du type générique au constructeur et de la conserver en tant que propriété interne juste comme Implémentation Java.util.EnumMap.
http://docs.Oracle.com/javase/1.5.0/docs/api/Java/util/EnumMap.htmlhttp://grepcode.com/file/repository.grepcode. com/Java/root/jdk/openjdk/6-b14/Java/util/EnumMap.Java
public class ContainerTest<T> {
Class<T> type;
T t;
public ContainerTest(Class<T> type) {
this.type = type;
}
public void setT(T t) {
this.t = t;
}
public T getT() {
return t;
}
public void doSomething() {
//There you can use "type" property.
}
}
Non, ce n'est pas possible à cause de type erasure (les paramètres de type sont compilés en tant que Object + types). Si vous vraiment devez connaître/appliquer le type au moment de l'exécution, vous pouvez stocker une référence à un objet Class
.
public class ContainerTest<T> {
private final Class<T> klass;
private final List<T> list = new ArrayList<T>();
ContainerTest(Class<T> klass) {
this.klass = klass;
}
Class<T> getElementClass() {
return klass;
}
void add(T t) {
//klass.cast forces a runtime cast operation
list.add(klass.cast(t));
}
}
Utilisation:
ContainerTest<String> c = new ContainerTest<>(String.class);
Pour apprendre la valeur de T
, vous devez la capturer dans une définition de type en sous-classant ContainerTest:
class MyStringClass extends ContainerTest<String> {}
Vous pouvez également le faire avec une classe anonyme si vous voulez:
ContainerTest<String> myStringClass = new ContainerTest<String>{}();
Ensuite, pour résoudre la valeur de T, vous pouvez utiliser TypeTools :
Class<?> stringType = TypeResolver.resolveRawArgument(ContainerTest.class, myStringClass.getClass());
assert stringType == String.class;
Si vous pouvez définir comme ceci
public class ContainerTest<T>
{
public void doSomething(T clazz)
{
}
}
Alors c'est possible
There is est un moyen d’obtenir le type d’exécution du paramètre type en utilisant TypeToken
de Guava pour le capturer. L'inconvénient de la solution est que vous devez créer une sous-classe anonyme chaque fois que vous avez besoin d'une instance de Container
.
class Container<T> {
TypeToken<T> tokenOfContainedType = new TypeToken<T>(getClass()) {};
public Type getContainedType() {
return tokenOfContainedType.getType();
}
}
class TestCase {
// note that containerTest is not a simple instance of Container,
// an anonymous subclass is created
private Container<String> containerTest = new Container<String>() {};
@Test
public void test() {
Assert.assertEquals(String.class, containerTest.getContainedType());
}
}
La clé de cette solution est décrite dans le JavaDoc du constructeur de TypeToken
utilisé dans le code ci-dessus:
Les clients créent une sous-classe anonyme anonyme. Cela incorpore le paramètre type dans la hiérarchie des types de la classe anonyme afin que nous puissions le reconstituer au moment de l'exécution malgré l'effacement.