我见过类似的问题,但他们没有多大帮助。
例如,我有这个通用类:
public class ContainerTest<T>
{
public void doSomething()
{
//I want here to determinate the Class of the type argument (In this case String)
}
}
和另一个使用此容器类的类
public class TestCase
{
private ContainerTest<String> containerTest;
public void someMethod()
{
containerTest.doSomething();
}
}
是否可以在方法doSomething()中确定类型参数的类,而具有显式类型变量/字段或任何构造函数在ContainerTest类中?
更新:更改了ContainerTest类的格式
答案 0 :(得分:13)
唯一的方法是将类存储在实例变量中,并将其作为构造函数的参数:
public class ContainerTest<T>
{
private Class<T> tClass;
public ContainerTest(Class<T> tClass) {
this.tCLass = tClass;
}
public void doSomething()
{
//access tClass here
}
}
答案 1 :(得分:10)
如果您对反思方式感兴趣,我在这篇很棒的文章中找到了部分解决方案: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<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());
}
}
答案 2 :(得分:5)
没有“干净”的方法从类中获取Generic Type参数。 相反,一个常见的模式是将Generic Type的Class传递给构造函数,并将其保存为java.util.EnumMap实现中的内部属性juste。
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<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.
}
}
答案 3 :(得分:2)
没有。由于type erasure(类型参数被编译为Object +类型转换),因此无法实现。如果确实需要在运行时知道/强制执行该类型,则可以存储对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));
}
}
使用:
ContainerTest<String> c = new ContainerTest<>(String.class);
答案 4 :(得分:1)
要了解T
的值,您需要通过继承ContainerTest在类型定义中捕获它:
class MyStringClass extends ContainerTest<String> {}
如果需要,您也可以使用匿名类执行此操作:
ContainerTest<String> myStringClass = new ContainerTest<String>{}();
然后要解析T的值,您可以使用TypeTools:
Class<?> stringType = TypeResolver.resolveRawArgument(ContainerTest.class, myStringClass.getClass());
assert stringType == String.class;
答案 5 :(得分:0)
如果您可以这样定义
public class ContainerTest<T>
{
public void doSomething(T clazz)
{
}
}
然后可能
答案 6 :(得分:0)
是一种通过使用Guava的TypeToken
捕获它来获取类型参数的运行时类型的方法。解决方案的缺点是每次需要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());
}
}
此解决方案的关键在上面代码中使用的TypeToken
构造函数的JavaDoc中描述:
客户端创建一个空的匿名子类。这样做会将类型参数嵌入到匿名类的类型层次结构中,因此我们可以在运行时重新构建它,尽管擦除。