在网上看到如下代码,不知道为什么报错,代码如下:
public class GenericTest {
public static void main(String[] args) throws Exception {
List<? super Fruit> f0=new ArrayList<Fruit>();
f0.add(new Apple());
f0.add(new Fruit());
f0.add(new SupApple());
List<? super Fruit> f1=new ArrayList<Apple>();
f1.add(new Apple());
f1.add(new Fruit());
List<? extends Fruit> f2=new ArrayList<Fruit>();
f2.add(new Apple());
f2.add(new Fruit());
List<? extends Fruit> f3=new ArrayList<Apple>();
f3.add(new Apple());
f3.add(new Fruit());
List<? super Apple> f5=new ArrayList<Fruit>();
f5.add(new Apple());
f5.add(new SupApple());
f5.add(new Fruit());
}
}
class Fruit{
}
class Apple extends Fruit{
}
class SupApple extends Apple{
}
首先说下extends和super的却别(参考:点击打开链接):
extends
List<? extends Number> foo3的通配符声明,意味着以下的赋值是合法的:List<?
extends
Number> foo3 =
new
ArrayList<?
extends
Number>();
List<?
extends
Number> foo3 =
new
ArrayList<?
extends
Integer>();
List<?
extends
Number> foo3 =
new
ArrayList<?
extends
Double>();
- 读取操作通过以上给定的赋值语句,你一定能从foo3列表中读取到的元素的类型是什么呢?你可以读取到Number,因为以上的列表要么包含Number元素,要么包含Number的类元素。
你不能保证读取到Integer,因为foo3可能指向的是List<Double>。
你不能保证读取到Double,因为foo3可能指向的是List<Integer>。
- 写入操作过以上给定的赋值语句,你能把一个什么类型的元素合法地插入到foo3中呢?
你不能插入一个Integer元素,因为foo3可能指向List<Double>。
你不能插入一个Double元素,因为foo3可能指向List<Integer>。
你不能插入一个Number元素,因为foo3可能指向List<Integer>。
你不能往List<? extends T>中插入任何类型的对象,因为你不能保证列表实际指向的类型是什么,你并不能保证列表中实际存储什么类型的对象。唯一可以保证的是,你可以从中读取到T或者T的子类。
super
现在考虑一下List<? super T>。List<? super Integer> foo3的通配符声明,意味着以下赋值是合法的:
List<?
super
Integer> foo3 =
new
ArrayList<Integer>();
List<?
super
Integer> foo3 =
new
ArrayList<Number>();
List<?
super
Integer> foo3 =
new
ArrayList<Object>();
- 读取操作通过以上给定的赋值语句,你一定能从foo3列表中读取到的元素的类型是什么呢?你不能保证读取到Integer,因为foo3可能指向List<Number>或者List<Object>。
你不能保证读取到Number,因为foo3可能指向List<Object>。
唯一可以保证的是,你可以读取到Object或者Object子类的对象(你并不知道具体的子类是什么)。
- 写入操作通过以上给定的赋值语句,你能把一个什么类型的元素合法地插入到foo3中呢?你可以插入Integer对象,因为上述声明的列表都支持Integer。
你可以插入Integer的子类的对象,因为Integer的子类同时也是Integer,原因同上。
你不能插入Double对象,因为foo3可能指向ArrayList<Integer>。
你不能插入Number对象,因为foo3可能指向ArrayList<Integer>。
你不能插入Object对象,因为foo3可能指向ArrayList<Integer>。
通过网上查找,最终明白了:
public static void main(String[] args) throws Exception {
//定义正确,使用正确。
List<? super Fruit> f0 = new ArrayList<Fruit>();
f0.add(new Apple());
f0.add(new Fruit());
f0.add(new SupApple());
List<? super Fruit> f1 = new ArrayList<Apple>(); // ArrayList泛型中的只能是Fruit或者Object,即Fruit本身或者Fruit的父类类型。
f1.add(new Apple());
f1.add(new Fruit());
//定义正确,使用错误。
List<? extends Fruit> f2 = new ArrayList<Fruit>();
//添加了Apple,f2有可能指向ArrayList<SupApple>
f2.add(new Apple());
//添加了Fruit,f2有可能指向ArrayList<SupApple>/ArrayList<Apple>
f2.add(new Fruit());
//定义正确,使用错误。
List<? extends Fruit> f3 = new ArrayList<Apple>();
//添加了Apple,f3有可能指向ArrayList<SupApple>
f3.add(new Apple());
//添加了Apple,f3有可能指向ArrayList<SupApple>/ArrayList<Apple>
f3.add(new Fruit());
//只能添加Apple以及Apple的子类
List<? super Apple> f5 = new ArrayList<Fruit>();
f5.add(new Apple());
f5.add(new SupApple());
f5.add(new Fruit());
/**
* 总结:
* extends,只能读取,不能写。
* super:可以读取,且只能返回Object类型,或Object的子类对象(但是不能确定具体的子类是什么)
* 可以写,? super Xxx ,只能写Xxx或Xxx的子类对象。
*/
}