擦除的神秘之处
当你开始更深入地专研泛型时,会发现有大量的东西初看起来是没有意义的。例如,尽管可以声明ArrayList.class
,但是不能声明 ArrayList
//:generics/ErasedTypeEquivalence.java
import java.util.*;
public class ErasedTypeEquivalence {
public static void main(String[] args) {
Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
System.out.println(c1 == c2);
}
} /* Output:
true
*///:~
ArrayList
ArrayList
在泛型代码内部,无法获得任何有关泛型参数类型的信息。**
Java泛型是使用擦除来实现的,这意味着当你在使用泛型时,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象。因此 List
为什么要擦除?(迁移兼容性)
擦除是 Java 的泛型实现的一种折中,因为泛型不是Java语言出现时就有的组成部分,所以这种折中是必需的。
在基于擦除的实现中,泛型类型被当作第二类类型处理,即不能在某些重要的上下文环境中使用的类型。泛型类型只有在静态类型检查期间才出现,在此之后,程序中的所有泛型类型都将被擦除,替换为它们的非泛型上界。例如,诸如 List
**
擦除的核心动机是它使得泛化的客户端可以用非泛化的类库来使用,反之亦然,这经常被称为“迁移兼容性”。
擦除的问题
擦除的代价是显著的。泛型不能用于显式地引用运行时类型的操作之中,例如转型、instanceof 操作和 new 表达式。因为所有关于参数的类型信息都丢失了。
任何基本类型都不能作为类型参数
不能创建参数化类型的数组
不能实例化类型变量
不能构造泛型数组