前言
String是Object的子类,因此下面的代码是合法的。
Object obj = new String();
但是,下面这段代码是不合法的。
ArrayList<Object> list = new ArrayList<String>();
原因就是,泛型是不变的(invariant)。泛型通配符就是解决这一问题的,可以增大代码的灵活性。
<? extends E>
<? extends E>
是上限通配符,限定了类型的上限(这里的上,指的的是类继承图中的位置),?必须是E的子类。
以下图的继承关系为例,这些代码都是合法的。
ArrayList<? extends animal> list = new ArrayList<animal>();
ArrayList<? extends animal> list = new ArrayList<cat>();
ArrayList<? extends animal> list = new ArrayList<dog>();
存入元素
由于<? extends E>
只指定了类型的上限,因此,list中存放的是E的子类,但编译器无法确定是哪个子类,因此无法加入元素。例如:
ArrayList<? extends animal> list = new ArrayList<cat>();
list.add(new dog());
虽然dog是animal的子类,但是,此时的list实际上是指向ArrayList
取得元素
由于<? extends E>
指定了类型的上限,因此,我们获得的所有元素,都是animal的子类,因此下面的语句是合法的。
ArrayList<? extends animal> list = new ArrayList<cat>();
animal t = list.get(0);
<? super E>
<? super E>
是上限通配符,限定了类型的上限,?必须是E的父类。
存入元素
list中存放的是E或E的父类,因此,list是一定可以存储E
或E
的子类的。因此下面的代码是合法的。
ArrayList<? super dog> list = new ArrayList<animal>();
list.add(new dog());
取得元素
list中存放的是E或E的父类,因此,我们只能确定,我们所取得的元素是Object的子类。因此下面的代码是合法的。
ArrayList<? super dog> list = new ArrayList<animal>();
Object obj = list.get(0);
PECS法则
PECS是"Producer-extends, Consumer-super"的简写。
我们看到,<? extends E>适合于取元素的场景(生产者);<? super E>可以存入E类型的数据,适合于取元素的场景(消费者)。
如果是既要存、也要取的集合,那么不适合使用泛型通配符。