假设我有这样的课程:
public class Foo<T, M> {
Pair<T, M> bar;
}
有没有办法在运行时确定“T”和“M”是什么?例如
Foo<String, Integer> foo1 = new Foo<String, Integer>();
Foo<Integer, Boolean> foo2 = new Foo<Integer, Boolean>();
// what happens next?
谢谢!
假设我有这样的课程:
public class Foo<T, M> {
Pair<T, M> bar;
}
有没有办法在运行时确定“T”和“M”是什么?例如
Foo<String, Integer> foo1 = new Foo<String, Integer>();
Foo<Integer, Boolean> foo2 = new Foo<Integer, Boolean>();
// what happens next?
谢谢!
不,没有。这几乎就是类型擦除的定义。
也就是说,有一些时髦的解决方法。您可以显式查找该对的组件,并询问它们的类型。您可以对匿名内部类使用很酷的技巧,例如 GuavaTypeToken
使用的——你不能new Foo<String, Integer>()
在运行时确定类型,但你可以在运行时确定类型new Foo<String, Integer>() {}
——注意匿名内部类,它确实保留了泛型参数为其超类指定,即Foo
. (披露:我为 Guava 做出了贡献。)
通常,最好的解决方案是首先避免需要这些信息。没有关于如何做到这一点的通用食谱,但通常是可能的。
综上所述,解决此需求的唯一通用解决方案是Class
显式传递元数据。
运行时通用信息将被删除。一旦你的类编译,所有的泛型类型信息将被删除和替换:
泛型类型中的所有类型参数及其边界或 Object(如果类型参数是无界的)
实际上,java.lang.reflect.Field
保留了通用信息;因此,通过反射,您可以获得通用信息,但仅限于类/实例变量(不是方法返回类型,也不是局部变量)。
因此,在您的情况下,如果 foo1 和 foo2 是某个类中的实例变量:
class FooTest {
Foo<String, Boolean> foo1;
}
然后FooTest.class.getDeclaredField("foo1").getGenericType()
将返回一个ParameterizedType
实例,您可以在其中检查getActualTypeArguments()
.