Java 泛型学习总结 (3)

现在可以使用 List 或类型为 A 的父类调用 insertElements() ,如下类:

List<A> listA = new ArrayList<A>(); insertElements(listA); List<Object> listObject = new ArrayList<Object>(); insertElements(listObject);

但是,insertElements() 方法无法从 List 中读取元素,除非它将读取到的对象强制转换为 Object 。 调用 insertElements() 时,List 中已经存在的元素可以是 A 类或其父类的任何类型,但不可能确切地知道它是哪个类。 由于 Java 所有的类都是 Object 的子类,因此如果将它们转换为 Object ,则可以从列表中读取对象。如下代码是正确的:

Object object = list.get(0);

但是如下代码是错误的,因为父类对象不能转换为子类对象:

A object = list.get(0); 泛型擦除

Java 的泛型是伪泛型,几乎仅仅提供编译时检查,泛型确保了只要在编译时不出现错误,运行时就不出现强制转换异常。在编译完成后,所有的泛型信息都会被擦除掉。List 和 List 等类型在编译后都会变成 List ,泛型附带的类型信息对 JVM 是不可见的。

定义 2 个分别处理 List 和 List 元素的 processElements() 函数,代码如下:

public void processElements(List<String> elements) { } public void processElements(List<Integer> elements) { }

编译器会报如下错误:
Error:(12, 17) java: 名称冲突: processElements(java.util.List<java.lang.Integer>)和processElements(java.util.List<java.lang.String>)具有相同疑符

意思就是我们定义了 2 个重复的方法,即两个方法的参数是一样的,说明虽然泛型参数不一样,但到底 List 和 List 是一个东西,它们的原始类型是一样的,都是同一个 List 类对象,可以使用如下代码验证:

Class strListClass = new ArrayList<String>().getClass(); Class intListClass = new ArrayList<Integer>().getClass(); System.out.println(strListClass); // class java.util.ArrayList System.out.println(intListClass); // class java.util.ArrayList System.out.println(strListClass == intListClass); // ture

原始类型(raw type)就是擦除(crased)掉泛型信息后的真正类型,泛型参数信息会被擦除,运行时最终使用 Object 或具体的限定类。

如 Class strListClass = new ArrayList<String>().getClass(); 编译后会变成 Class strListClass = new ArrayList().getClass();

Java 为什么只把泛型信息留在编译阶段?
Java不能实现真正泛型的原因? - RednaxelaFX的回答 - 知乎

其他

JDK 文档中经常能看到 T、K、V、E、N 等类型参数,实际上这些符号随意选择使用也是没问题的,甚至可以使用如 A、B 等,但建议和 JDK 文档风格保持一致,至少得让人容易理解。
常见各符号的含义:

T:type
K:key
V:value
E:element
N:Number

泛型数组

在 Java 中不能创建一个确切泛型类型的数组,如下代码是不允许的:

List<String>[] strLists = new ArrayList<String>[8];

将会报错:Error:(11, 27) java: 创建泛型数组。

但是使用通配符创建泛型数组是可以的,比如下面代码是被允许的:

List<?>[] strLists = new ArrayList<?>[8];

为什么?
Java为什么不支持泛型数组? - 蜗牛学院的回答 - 知乎

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspysj.html