java泛型类型擦除

Fia*_*ary 3 java generics type-erasure

声明类型参数的类时 <T extends A & B & C>,类型擦除过程将替换T为类型A.但是,如果类型的变量T调用方法,接口声明BC,什么是Java的关系呢?

当我们创建泛型类型的实例时ArrayList<String>,类型参数String也将被删除,但调用get方法将返回类型 String,这些信息来自何处,因为它已被删除?

我知道使用java反射,但我需要一些具体的解释.

Jon*_*eet 6

不使用反射 - 铸造是.例如,请使用以下代码:

interface A {
    void a();
}

interface B {
    void b();
}

interface C {
    void c();
}

class Generic<T extends A & B & C> {
    T t;

    Generic(T t) {
        this.t = t;
    }

    void callMethods() {
        t.a();
        t.b();
        t.c();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在看一下Generic(构造函数已删除)的字节码:

class Generic extends java.lang.Object{
A t;

void callMethods();
  Code:
   0:   aload_0
   1:   getfield        #2; //Field t:LA;
   4:   invokeinterface #3,  1; //InterfaceMethod A.a:()V
   9:   aload_0
   10:  getfield        #2; //Field t:LA;
   13:  checkcast       #4; //class B
   16:  invokeinterface #5,  1; //InterfaceMethod B.b:()V
   21:  aload_0
   22:  getfield        #2; //Field t:LA;
   25:  checkcast       #6; //class C
   28:  invokeinterface #7,  1; //InterfaceMethod C.c:()V
   33:  return    
}
Run Code Online (Sandbox Code Playgroud)

checkcast在每次invokeinterface调用b()和之前请注意说明c().

结果就好像Generic实际上是这样编写的:

class Generic<T extends A> {
    T t;

    Generic(T t) {
        this.t = t;
    }

    void callMethods() {
        t.a();
        ((B) t).b();
        ((C) t).c();
    }
}
Run Code Online (Sandbox Code Playgroud)

至于你的问题ArrayList- 关于get()作为列表元素类型的返回类型的信息仍然存储为ArrayList类的一部分.编译器将再次在调用代码中插入强制转换,因此:

ArrayList<String> strings = new ArrayList<String>();
strings.add("foo");
String x = strings.get(0);
Run Code Online (Sandbox Code Playgroud)

在执行时相当于:

ArrayList strings = new ArrayList();
strings.add("foo");
String x = (String) strings.get(0);
Run Code Online (Sandbox Code Playgroud)

这样做的一个重要方面是,您无法在执行时询问ArrayList对象什么T- 该信息已被删除.