
上QQ阅读APP看书,第一时间看更新
6.1.3 Java通过类型擦除支持泛型
相比C++和C#,Java的泛型可能会被认为是“伪泛型”。这是由于Java为了兼容性的考虑,采用类型擦除的机制来支持泛型。
泛型信息只存在于代码编译阶段,在进入JVM之前,与泛型相关的信息会被擦除掉,这个过程被称为类型擦除。
1.类型擦除
List<String>和List<Integer>在编译之后都会变成List<Object>,例如:

通过javap -c命令对上述代码反汇编,并不能发现list1、list2泛型参数的类型:

于是,分别打印list1、list2的类型,再次验证一下类型擦除。
System.out.println(list1.getClass()); System.out.println(list2.getClass());
执行结果如下:
class java.util.ArrayList class java.util.ArrayList
因此,List<T>在运行时并不知道泛型参数的类型。
2.Java数组并没有受到类型擦除的影响
Java不支持泛型数组,它也不会受到类型擦除的影响,例如:
String[] array1 = new String[5]; array1[0] = "kotlin";
Integer[] array2 = new Integer[5]; array2[0] = 1;
通过javap -c命令对代码进行反汇编,能够看出array1、array2的类型。

再分别打印array1、array2的类型来进行验证:
System.out.println(array1.getClass()); System.out.println(array2.getClass());
执行结果如下:
class [Ljava.lang.String; class [Ljava.lang.Integer;
由此可见,数组在运行时可以获得它的类型。因为Java数组是协变的,Java不支持泛型数组。
协变是在计算机科学中描述具有父/子型别关系的多个型别通过型别构造器构造出的多个复杂型别之间是否有父/子型别关系的用语。
在6.2节会详细介绍Kotlin的协变。