泛型擦除后仍然保留的泛型信息

泛型擦除后仍然保留的泛型信息

我们知道泛型擦除会擦除泛型类型,转而使用原始类型或类型上界。那么有关泛型的信息在编译完成后一点都不会保留吗?其实,还是有保留的,这些信息保留在字节码指令集之外的地方。

具体哪些泛型信息会被保留呢?总结来说就是声明、定义处的泛型信息会被保留,比如:泛型接口、类、方法定义、成员变量的声明等。

代码验证

先准备一个接口和一个实现类

interface Animal<T, K> {
    void eat(K k);
}

class Dog<T, K> implements Animal<T, K> {
    private T t;
    ArrayList<T> list = new ArrayList<>();

    @Override
    public void eat(K k) {
        List<K> list = new ArrayList<>();
        list. Add(k);
    }
}

执行以下命令查看接口的字节码信息

javap -c -p -s Animal.class
Compiled from "GenericErasureExample2.java"
interface com.foo.Animal<T, K> {
  public abstract void eat(K);
    descriptor: (Ljava/lang/Object;)V
}

从接口的字节码信息中,可以看到接口Animal定义的泛型 T、K都在声明处被保留,方法的形参类型K 也被保留。

接下来看一下实现类Dog

javap -c -p -s Dog.class
Compiled from "GenericErasureExample2.java"
class com.foo.Dog<T, K> implements com.foo.Animal<T, K> {
  private T t;
    descriptor: Ljava/lang/Object;

  java.util.ArrayList<T> list;
    descriptor: Ljava/util/ArrayList;

  com.foo.Dog();
    descriptor: ()V
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: new           #2                  // class java/util/ArrayList
       8: dup
       9: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
      12: putfield      #4                  // Field list:Ljava/util/ArrayList;
      15: return

  public void eat(K);
    descriptor: (Ljava/lang/Object;)V
    Code:
       0: new           #2                  // class java/util/ArrayList
       3: dup
       4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
       7: astore_2
       8: aload_2
       9: aload_1
      10: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      15: pop
      16: return
}

Dog的输出结果,不仅类的声明处,泛型信息得以保留,而且实现接口的声明处泛型也保留了。

成员变量 t和 list 的泛型信息也是保留的,方法的形参类型也是保留的,构造函数也是一样会保留,和方法同理。

既然保留了泛型信息,那么能获取到泛型的具体类型吗

如果你想用反射的方式获取泛型的具体类型是做不到的,能获取到的仅仅是泛型的定义,比如<T>。

因为Java实现泛型的原理是泛型擦除,所以不可能知道泛型的具体类型。

发表评论

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