Java:在运行时获取泛型类参数

时间:2012-09-17 19:17:01

标签: java generics parameterized

我有两个班,一个抽象,一个具体:

abstract class Generator<T>;
class ConGenerator<T extends Complex<Z,Y>, Z extends Something1, Y extends Something2> extends Generator<T>;

由于参数数量的变化(我认为),我无法在运行时使用ParametrizedType的常规方法获取参数类,即

ParameterizedType genericSuperclass = (ParameterizedType)getClass().getGenericSuperclass();
Type[] type = genericSuperclass.getActualTypeArguments();

我得到的只是我用于参数的名称T。我很感激有任何帮助解决这个问题,我已经在网上搜索并使用了其他人为这些问题写的一些图书馆;到目前为止没有运气。

1 个答案:

答案 0 :(得分:1)

问题

在给定运行时类的情况下,并不总是可以推断出类型参数,而你的类型参数就是这种情况。根本问题是泛型类的所有实例(不论其类型参数)共享相同的运行时类,即:

new ArrayList<Integer>().getClass() == new ArrayList<String>().getClass()

因此,如果该类是通用的并且该类的不同实例可以对type参数使用不同的值,则不可能仅仅发现运行时类给出的类型参数。 (是的,我们可以找到类X<T extends String>的类型参数,因为String是final,因此是唯一可能的参数。同样,如果我们知道运行时类是{{1},我们可以找到List的类型参数})。

相反,如果运行时类不是通用的,那么总是可以推断超类的类型参数 - 这就是所有那些浮动在网络上的库和代码示例都具有不同程度的复杂性。例如,如果你有:

class MappedList<T> implements List<String> { ... }

你可以发现ArrayList的类型参数是class StringArrayList extends ArrayList<String> { ... } 。这也适用于匿名类(只要它们不是通用的),因为:

String

但是失败了,如

这样的泛型类
new ArrayList<String>() {}.getClass() != new ArrayList<Integer>() {}.getClass()

,因为

ArrayList<T> makeList(T t) {
    return new ArrayList<T>(t) {};
}

解决方案

如果在运行时需要该类型,则需要通过其他方式提供它,通常是将makeList("2").getClass() == makeList(2).getClass() 对象传递给构造函数。您还可以使用超类型令牌(所需类型的非泛型,通常是匿名的子类的实例,它允许您通过反射发现类型参数)。这样做的好处是,也可以表达本身通用的类型参数。

如果你只需要特定的课程,可能会有更简单的选择。例如,如果您只需要创建type参数的新实例,则工厂(方法)模式可以更简单: - )