擦除-编译后的通用类型信息

时间:2019-05-30 19:57:25

标签: java generics type-erasure

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

//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; }
}

编译这两个类之后,T中的Gen将被Object替换。中的T 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文件仍然显示Formal Type参数<T>

2 个答案:

答案 0 :(得分:3)

  

.class文件为什么仍显示Formal Type参数?

简单:这样

  • 在编译时,编译器可以读取此类.class文件,并了解相应的类是 generic ,并且可以在源代码中用作generic
  • 在运行时,以便某些代码可以检查并“反思”该类的一般性质

类型擦除是指以下事实:未保留有关用于实例化泛型类的特定类型的信息。但是该类是通用的信息需要在类文件中。在编译器看不到Gen.java而是只看到Gen.class的情况下,编译器又如何知道Gen是通用的呢?

答案 1 :(得分:1)

关于该类

类型信息仍然保留。不是有关个体实例的类型信息。

因此,您知道Gen有一个类级别的类型参数(名义上)称为T

在运行时,您不知道T实例的Gen。您甚至无法从getob来确定它:仅给您类型的下限(例如,如果getob返回StringT可能是{{ 1}},StringCharSequenceSerializable)。如果返回Object,则null可以是任何东西。

您可以使用Java针对没有源的类(只有编译后的字节码)编写代码。编译器需要有关此类的泛型的信息,以便能够确保正确使用它们。