问题
给定运行时类,并不总是可以推断类型参数,而您的情况就是这样。根本问题是泛型类的所有实例(无论它们的类型参数如何)共享相同的运行时类,即:
new ArrayList<Integer>().getClass() == new ArrayList<String>().getClass()
因此,如果该类是泛型的并且该类的不同实例可以对类型参数使用不同的值,则不可能发现仅给定运行时类的类型参数。(是的,我们可以找到 class 的类型参数X<T extends String>
,因为 String 是 final,因此是唯一可能的参数。同样,如果我们知道运行时类是,我们可以找到 List 的类型参数class MappedList<T> implements List<String> { ... }
)。
相反,如果运行时类不是泛型的,则总是可以推断出超类的类型参数——这就是所有那些在网上漂浮的库和代码示例所做的各种复杂程度的操作。例如,如果您有:
class StringArrayList extends ArrayList<String> { ... }
您会发现 ArrayList 的类型参数是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()
解决方案
如果您在运行时需要该类型,则需要通过其他方式提供它,通常是通过将Class
对象传递给构造函数。您还可以使用超类型标记(所需类型的非泛型,通常是匿名的子类的实例,它允许您通过反射发现类型参数)。这样做的好处是也可以表达本身是泛型的类型参数。
如果您只需要特定事物的类,则可能有更简单的选择。例如,如果您只需要创建类型参数的新实例,工厂(方法)模式就简单多了:-)