如何在Javagenerics中获取类型变量的类

我见过类似的问题,但他们没有多大帮助。

例如,我有这个通用类:

public class ContainerTest { public void doSomething() { //I want here to determinate the Class of the type argument (In this case String) } } 

和另一个使用此容器类的类

 public class TestCase { private ContainerTest containerTest; public void someMethod() { containerTest.doSomething(); } } 

是否有可能在方法doSomething()中确定类型参数的类而没有显式类型变量/字段或ContainerTest类中的任何构造函数

更新:更改ContainerTest类的格式

唯一的方法是将类存储在实例变量中,并将其作为构造函数的参数:

 public class ContainerTest { private Class tClass; public ContainerTest(Class tClass) { this.tCLass = tClass; } public void doSomething() { //access tClass here } } 

如果您对reflection方式感兴趣,我在这篇很棒的文章中找到了部分解决方案: http : //www.artima.com/weblogs/viewpost.jsp?thread = 208860

简而言之,您可以使用java.lang.Class.getGenericSuperclass()java.lang.reflect.ParameterizedType.getActualTypeArguments()方法,但您必须子类化一些父超类。

以下代码段适用于直接扩展超类AbstractUserType的类。 有关更一般的解决方案,请参阅参考文章

 import java.lang.reflect.ParameterizedType; public class AbstractUserType { public Class returnedClass() { ParameterizedType parameterizedType = (ParameterizedType) getClass() .getGenericSuperclass(); @SuppressWarnings("unchecked") Class ret = (Class) parameterizedType.getActualTypeArguments()[0]; return ret; } public static void main(String[] args) { AbstractUserType myVar = new AbstractUserType() {}; System.err.println(myVar.returnedClass()); } } 

从类中获取Generic Type参数没有“干净”的方法。 相反,常见的模式是将通用类的类传递给构造函数,并将其作为内部属性juste保留,如java.util.EnumMap实现中所做的那样。

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/EnumMap.html http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk /6-b14/java/util/EnumMap.java

 public class ContainerTest { Class type; T t; public ContainerTest(Class 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. } } 

不可以。由于类型擦除是不可能的(类型参数被编译为Object +类型转换)。 如果您确实需要在运行时知道/强制执行该类型,则可以存储对Class对象的引用。

 public class ContainerTest { private final Class klass; private final List list = new ArrayList(); ContainerTest(Class klass) { this.klass = klass; } Class getElementClass() { return klass; } void add(T t) { //klass.cast forces a runtime cast operation list.add(klass.cast(t)); } } 

使用:

 ContainerTest c = new ContainerTest<>(String.class); 

要了解T的值,您需要通过inheritanceContainerTest在类型定义中捕获它:

 class MyStringClass extends ContainerTest {} 

如果需要,您还可以使用匿名类执行此操作:

 ContainerTest myStringClass = new ContainerTest{}(); 

然后要解析T的值,可以使用TypeTools :

 Class stringType = TypeResolver.resolveRawArgument(ContainerTest.class, myStringClass.getClass()); assert stringType == String.class; 

如果您可以这样定义

 public class ContainerTest { public void doSomething(T clazz) { } } 

那么这是可能的

有一种方法可以通过使用Guava的TypeToken来获取类型参数的运行时类型。 解决方案的缺点是每次需要Container实例时都必须创建一个匿名子类。

 class Container { TypeToken tokenOfContainedType = new TypeToken(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 containerTest = new Container() {}; @Test public void test() { Assert.assertEquals(String.class, containerTest.getContainedType()); } } 

在上面的代码中使用的TypeToken构造函数的JavaDoc中描述了此解决方案的关键:

客户端创建一个空的匿名子类。 这样做会在匿名类的类型层次结构中嵌入type参数,因此我们可以在运行时重新构建它,尽管擦除。