Java泛型通配符

前言

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是一定可以存储EE的子类的。因此下面的代码是合法的。

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类型的数据,适合于取元素的场景(消费者)。
如果是既要存、也要取的集合,那么不适合使用泛型通配符。

posted @ 2020-08-07 23:02  阳离子  阅读(180)  评论(0编辑  收藏  举报