在 Java 中对于下面最简单的泛型类
class A<T> {
public void foo() {
//如何在此处获得运行时 T 的具体类型呢?
}
}
设想我们使用时
new A<String>().foo();
是否能在 foo()
方法中获得当前的类型是 String 呢?答案是否定的,不能。在 foo()
方法中 this 引用给不出类型信息,this.getClass()
就更不可能了,因为 Java 的泛型不等同于 C++ 的模板类,this.getClass()
实例例是被所有的不同具体类型的 A 实例(new A<String>(), new A<Integer>() 等) 共享的,所以在字节码中类型会被擦除到上限。
我们可以在 IDE 的调试时看到这个泛型类的签名
或者用 javap -v cc.unmi.A
可以查看到类 A 的泛型签名
Signature: #17 // <T:Ljava/lang/Object;>Ljava/lang/Object;
为什么说是擦除到上限呢?并不是泛型在字节码中都表示为 Object
, 看下面的例子,假如 A
声明如下
class A<T extends Number> {
}
再用 javap -v cc.unmi.A
来看泛型签名
Signature: #18 // <T:Ljava/lang/Number;>Ljava/lang/Object;
了解了 Java 泛型机制是如何擦除类型的,我们接下来的问题就是如何通过反射获得泛型签名中的类型,一般会在继承或实现泛型接口时会用到它。
class A<T, ID> {
}
class B extends A<String, Integer> {
}
interface A<T, ID> {
}
class B implements A<String, Integer> {
}
public class Generic {
public static void main(String[] args) {
Type superType = getClass().getGenericSuperclass();//如果使用继承
Type superType = getClass().getGenericInterfaces();//如果使用接口
//获得泛型列表
Type daoType = ((ParameterizedType) superType).getActualTypeArguments()[0];
}
}