Java 泛型学习总结 (2)

因为 A 是 B 和 C 类的共同父类,那么 List 是不是 List 和 List 的共同父类吗?换句话说,是否可以将 List 引用指向 List 对象呢?或者反过来让 List 引用指向 List 对象呢?

答案是不可以,第一种情况,父类引用指向子类对象,如将 List 引用指向 List 对象,先假设这是可以的,有如下代码:

List<A> listA = listB;

这会出现问题,因为 listA 是 List 类型,它可以放入任何 A 对象作为元素,可以放入 B 对象,也可以放入 C 对象,但是它实际指向的是一个 List 集合,List 集合中本应该只存储 B 类对象的,现在却不可预料地放入了 C 对象,这显然会引起麻烦,所以这种情况是不允许的。

第二种情况,让 List 引用指向 List 对象,这样肯定也是不可以的,因为已存在的 List 集合中,可能已经存在了 A 类的非 B 类子类对象,如 C 类对象,这样也不能保证从 List 集合中取出的元素一定就是 B 对象。

但是,确实存在需要使用泛型继承关系的情况,看如下代码:

public void processElements(List<A> elements){ for(A o : elements){ System.out.println(o.getValue()); // 这里假设的 A 类存在 getValue() 方法 } }

我们希望定义一个类,让其能处理所有指定类型元素的 List ,如 processElements(List elements) 方法,既可以处理 List ,也可以处理 List

类型通配符

有 3 中类型通配符用法,如下代码:

List<?> listUknown = new ArrayList<A>(); // 任何类型元素都可接受 List<? extends A> listUknown = new ArrayList<A>(); // 可接受 A 子类类型元素 List<? super A> listUknown = new ArrayList<A>(); // 可接受 A 父类类型元素

还可以有多个限定,比如限定要同时可比较和可序列化,就可以使用 <T extends Comparable & Serializable>

无边界类型通配符<?>

List<?> 表示未知类型的 List 。 这可以是 List,List 或 List 等。

由于不知道 List 的类型,所以只能从集合中读取,不能放入新元素,并且只能将读取的元素视为 Object 类型,如下例:

public void processElements(List<?> elements){ for(Object o : elements){ System.out.println(o); } }

现在 processElements() 方法可以使用任何泛型参数的 List 集合作为参数,如下:

List<A> listA = new ArrayList<A>(); processElements(listA); 上界类型通配符<? extends A>

这样将表示可接受的泛型参数,必须是 A 类或者 A 类的子类,A 类就是最大的范围,所以叫做上界。
定义如下方法:

public void processElements(List<? extends A> elements){ for(A a : elements){ System.out.println(a.getValue()); } }

这样,它可以接收 List, List 或 List 集合作为参数,如下:

List<A> listA = new ArrayList<A>(); processElements(listA); List<B> listB = new ArrayList<B>(); processElements(listB); List<C> listC = new ArrayList<C>(); processElements(listC);

processElements(List<? extends A> elements) 方法仍然无法插入元素到列表中,因为不知道传入的 List 中的元素的具体类型,它可能是 A, B 或 C 类 ,如果可以插入,那么取出来的时候就无法确认,强制转换就会失败。

但是可以读取元素,因为 List 里面保存的元素一定是 A 类或其子类对象,转换成 A 类不会报错。

下界类型通配符 <? super A>

这样将表示可接受的泛型参数,必须是 A 类(A 类的子类也属于 A 类)或者 A 类的父类,A 类就是最小的范围,所以叫做下界。
当知道 List 中的元素肯定是 A 类或 A 的父类时,可以安全地将 A 类的对象或 A 的子类对象(例如 B 或 C)插入 List 中。 下面是一个例子:

public static void insertElements(List<? super A> list){ list.add(new A()); list.add(new B()); list.add(new C()); }

此处插入的所有元素都是 A 类对象或 A 类的父类的对象。由于 B 和 C 都继承了 A ,如果 A 有一个父类,B 和 C 也将是该父类的对象。

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

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