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>()newArrayList()在运行时实际上只是一个新的,但如果一个类扩展ArrayList<String>,那么JVM知道这String是List'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>,因此类型参数保留在超类声明中.
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关于该主题的文章)。