首页 > 解决方案 > 擦除 - 编译后的通用类型信息

问题描述

我在一本书中遇到了以下内容-

//Here, T is bound by Object by default.
class Gen<T> {
    T ob; // here, T will be replaced by Object

    Gen(T o) {
        ob = o;
    }

//Return ob.
    T getob() {
        return ob;
    }
}

// Here, T is bound by String.
class GenStr<T extends String> {
    T str; // here, T will be replaced by String
    GenStr(T o) {
      str = o;
    }
    T getstr() { return str; }
}

这两个类编译完成后,TinGen将被替换为Object. Tin 将GenStr替换为String. javap您可以通过在他们编译的类上运行来确认这一点。结果显示在这里:

class Gen extends java.lang.Object{
    java.lang.Object ob;
    Gen(java.lang.Object);
    java.lang.Object getob();
}
class GenStr extends java.lang.Object{
    java.lang.String str;
    GenStr(java.lang.String);
    java.lang.String getstr();
}

然而,我看到了这个——

public class GenStr<T extends java.lang.String> {
  T str;

  GenStr(T);
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: aload_1
       6: putfield      #2                  // Field str:Ljava/lang/String;
       9: return

  T getstr();
    Code:
       0: aload_0
       1: getfield      #2                  // Field str:Ljava/lang/String;
       4: areturn
}

class Gen<T> {
  T ob;

  Gen(T);
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: aload_1
       6: putfield      #2                  // Field ob:Ljava/lang/Object;
       9: return

  T getob();
    Code:
       0: aload_0
       1: getfield      #2                  // Field ob:Ljava/lang/Object;
       4: areturn
}

为什么.class文件仍然显示正式类型参数<T>

标签: javagenericstype-erasure

解决方案


为什么 .class 文件仍然显示正式类型参数?

简单:这样

  • 在编译时,编译器可以读取这样的 .class 文件并理解相应的类是泛型的,并且可以在源代码中作为泛型使用
  • 在运行时,以便某些代码可以检查,嗯,“反映”该类的通用性质

类型擦除是指有关用于实例化泛型类的特定类型的信息不被保留的事实。但是这个类是通用的信息需要在类文件中。Gen在编译器看不到 Gen.java 而只看到 Gen.class 的情况下,编译器怎么会知道它是通用的?!


推荐阅读