类型擦除(type erasure)。 Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节代码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉。这个过程就称为类型擦除。如在代码中定义的List<Object>和List<String>等类型,在编译以后都会变成List。JVM看到的只是List,而由泛型附加的类型信息对JVM来讲是不可见的。Java编译器会在编译时尽量的发现可能出错的地方,可是仍然没法避免在运行时刻出现类型转换异常的状况。类型擦除也是Java的泛型实现方式与C++模板机制实现方式之间的重要区别。 java
不少泛型的奇怪特性都与这个类型擦除的存在有关,包括:
泛型类并无本身独有的Class类对象。好比并不存在List<String>.class或是List<Integer>.class,而只有List.class。
静态变量是被泛型类的全部实例所共享的。对于声明为MyClass<T>的类,访问其中的静态变量的方法仍然是 MyClass.myStaticVar。无论是经过new MyClass<String>仍是new MyClass<Integer>建立的对象,都是共享一个静态变量。 数据结构
当泛型碰见重载: spa
public class GenericTypes { public static void method(List<String> list) { System.out.println("invoke method(List<String> list)"); } public static void method(List<Integer> list) { System.out.println("invoke method(List<Integer> list)"); } }
这段代码是不能被编译的,是由于参数List<Integer>和List<String>编译以后都被擦除了,变成了同样的原生类型List<E>,擦除动做致使这两个方法的特征签名变得如出一辙。初步看来,没法重载的缘由已经找到了,可是真的就是如此吗?只能说,泛型擦除成相同的原生类型只是没法重载的其中一部分缘由。 code
public class GenericTypes { public static String method(List<String> list) { System.out.println("invoke method(List<String> list)"); return ""; } public static int method(List<Integer> list) { System.out.println("invoke method(List<Integer> list)"); return 1; } public static void main(String[] args) { method(new ArrayList<String>()); method(new ArrayList<Integer>()); } }两个method方法添加了不一样的返回值,因为这两个返回值的加入,方法重载竟然成功了,即这段代码能够被编译和执行了。这是咱们对Java语言中返回值不参与重载选择的基本认知的挑战吗?
重载固然不是根据返回值来肯定的,之因此此次能编译和执行成功,是由于两个mehtod()方法加入了不一样的返回值后才能共存在一个Class文件之中。Class文件方法表(method_info)的数据结构时曾经提到过,方法重载要求方法具有不一样的特征签名,返回值并不包含在方法的特征签名之中,因此返回值不参与重载选择,可是在Class文件格式之中,只要描述符不是彻底一致的两个方法就能够共存。也就是说两个方法若是有相同的名称和特征签名,但返回值不一样,那它们也是能够合法地共存于一个Class文件中的。
对象