为什么在运行时Java中没有删除所有类型信息?

Lar*_*ars 25 java generics type-erasure

我对Java Generics的明显错误理解到目前为止,Type Erasure删除了所有类型信息,以至于在运行时根本没有任何东西.最近我偶然发现了一个代码片段,我不得不问自己:黑客如何做到这一点?简化后,它表示为:

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public abstract class SuperClass<T> {

    private final Type type;

    protected SuperClass(){
        ParameterizedType parameterizedType =
                (ParameterizedType) getClass().getGenericSuperclass();
        type = parameterizedType.getActualTypeArguments()[0];
    }

    public void tellMyType(){
        System.out.println("Hi, my type parameter is " + type);
    }    
}
Run Code Online (Sandbox Code Playgroud)

public class Example {

    public static void main(String[] args) {
        SuperClass sc = new SuperClass<Integer>(){};
        sc.tellMyType();
    }
}
Run Code Online (Sandbox Code Playgroud)

执行主类导致Hi, my type parameter is class java.lang.Integer.

我们在这里可以看到,T的类型信息也可以在运行时获得,这与我最初的理解相矛盾.

所以我的问题是:为什么编译器保留这个?这是某些内部JVM行为所必需的,还是对此效果有任何合理的解释?

dan*_*ben 18

来自http://www.artima.com/weblogs/viewpost.jsp?thread=208860:

事实证明,虽然JVM不会跟踪泛型类实例的实际类型参数,但它会跟踪泛型类的子类的实际类型参数.换句话说,虽然 ArrayList<String>()new ArrayList()在运行时实际上只是一个新的,但如果一个类扩展ArrayList<String>,那么JVM知道这StringList's类型参数的实际类型参数.

在您的情况下,您正在创建参数化类型的匿名子类,因此保留类型信息.请参阅文章以获得深入的解释.


axt*_*avt 16

类型参数仅从动态类型(即正在创建的对象类型)中删除:

Object o = new ArrayList<String>(); // String erased
Run Code Online (Sandbox Code Playgroud)

它保留在静态类型中(即字段,参数和返回类型,throws子句,超类和超接口声明):

class Test implements Superclass<String> { // String retained 
    // Accessible via Class.getGenericSuperclass()

    private List<Integer> l; // Integer retained (via Field.getGenericType())

    public void test(List<Long> l) {} // Long retained (via Method.getGenericParameterTypes())

    // Character retained (via Method.getGenericReturnType())
    public List<Character> test() { return null; }
}
Run Code Online (Sandbox Code Playgroud)

在您的情况下,您创建了一个匿名子类SuperClass<Integer>,因此类型参数保留在超类声明中.


Ben*_*ngs 5

Google Guice使用它来创建TypeLiterals 来表示运行时的泛型类。例如

TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};
Run Code Online (Sandbox Code Playgroud)

可以使用,但是

Class<List<String>> list = List<String>.class;
Run Code Online (Sandbox Code Playgroud)

不会编译。

该技术被称为“超级类型令牌”(请参阅Neal Gafter关于该主题的文章)。