关于java:泛型擦除与反射获取泛型类型

Java中的泛型会被类型擦除,那为什么在运行期依然能够应用反射获取到具体的泛型类型?
上面从知乎上看到一个答案,现摘录如下:

在运行期只能获取以后class文件中蕴含泛型信息的泛型类型,而不能在运行时动静获取某个泛型援用的类型事实上所谓的泛型的类型擦除是指把某个具体的泛型援用在编译期实现类型查看后,擦除成了Object而失落了它运行时所赋予的类型信息。举例来说,真正没有擦除的泛型应该是能轻而易举地执行如下操作的:

public class Test<T> {
    public T[] getArray(int length) {
        Class<T> clazz = T.class;
        return (T[])Array.newInstance(clazz, length);
    }
}

在以上的代码中,假如泛型的信息没有被擦除,您在任何地位new进去的Test实例都会保留本人的“T”类型信息,那么getArray办法就能够获取到理论T的class信息。而在类型擦除后,下面代码中是没有任何方法在getArray办法外部获取到T的类型信息的,这才是擦除后的实际效果。您所说的能够通过反射获取到的泛型信息肯定是某个class作为成员变量、办法返回值等地位的具体泛型类型,举例来说:

public class Test<T> {
    private Test<Integer> test;

    private T item;
}

在下面的代码中,您能够通过反射获取成员test的Integer泛型信息,然而无奈获取item的理论类型。这部分我查看了OpenJDK 8的相干源码,从原理上讲,例子中的test成员编译时会将Integer信息编译进class字节码,从而反射零碎就能够获取到这个信息,如下图所示:


您能够看到,实际上test的泛型信息是间接被编译进字节码了。

而这个办法实质上的操作是从曾经加载好的class信息中获取fieldDescriptor,从而产生Field对象的oop,把class的field信息注入进去,返回给Java端的调用方。而再追溯class中产生fieldDescriptor的代码能够发现,事实上这个信息就是在JVM加载字节码的时候,JVM将解析到字节码的泛型信息保留下来的。也就说在类加载阶段,JVM就将字节码中写死的泛型信息保留了下来。而您反射的时候,反射零碎天然就能够获取到该信息,从而您能够通过getGenericType()来获取到Type信息,从而解析出泛型类型。

例子中定义的item这类泛型援用来说,它们的泛型信息不来自于本身的class,在编译实现通过类型查看后,类型零碎中它们就等同于Object,这种泛型是无奈通过反射获取的,也就是说这类类型信息被擦除了

作者:陆萌萌
链接:https://www.zhihu.com/questio…
起源:知乎
著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理