在stackoverflow上看到两篇关于java泛型 PECS 的问答:
PECS
Remember PECS:"Producer Extends,Consumer Super"
"Producer Extends" - If you need a List
to produce T
values (you want to read T
s from the list), you need to declare it with ? extends T
, e.g. List extends Integer>
. But you cannot add to this list.
"Consumer Super" - If you need a List
to consume T
values (you want to write T
s into the list), you need to declare it with ? super T
, e.g. List super Integer>
. But there are no guarantees what type of object you may read from this list.
If you need to both read from and write to a list, you need to declare it exactly with no wildcards, e.g. List
.
也就是说:
当你仅仅需要从List
中读出T
,那么你需要使用? extends T
.例如List extends Integer>
当你仅仅需要将T写入List
时,那么你需要使用? super T
.例如List super Integer>
当你既需要读也需要写时,你应该直接使用T. List< Integer>
PECS的使用
extends
List extends Number> foo
表示foo
可以存储一族的类型的值(而不是一个特殊的类型的值),所以下面的声明都是正确的:
List extends Number> foo = new ArrayList; // Number "extends" Number
List extends Number> foo = new ArrayList; // Integer extends Number
List extends Number> foo = new ArrayList; // Double extends Number
正因为foo
表示存储的是一族的类型的值,无法保证具体指向的类型,所以我们无法保证我们add
的对象是List
允许的类型。假如我们add
一个Integer
的值,但是foo
可能指向Double
(第三条语句),我们add
一个Double
的值,foo
可能指向Integer
(第二条语句)。
虽然无法add
,但是我们可以保证我们从foo
中取出来的值肯定是属于Number
或者是Number
的子类,所以我们可以从foo
中获取值。
super
关于List super T>
,以下声明是正确的:
List super Number> foo = new ArrayList; // Number is a "super" of Number
List super Number> foo = new ArrayList; // Object is a "super" of Number
因为foo
的类型无法确定,可能是Number
,也可能是Number
的父类,我们无法保证读出来的值的类型,所以无法从List
中读出值。但是我们可以保证我们插进去的值肯定属于Number
或者Number
的父类,因此我们可以使用add
。
JDK中的例子
Collections.copy()
的方法签名:
public static void copy(List super T> dest,List extends T> src)
在src
中,我们可以传入与T
类型相关的List
,并且能够保证取出的是T
类型或者T
的子类型的值。
在dest
中,我们可以传入T
类型和T
的父类的List
,并且能够保证我们从存放的值都满足要求。
例如:
// copy(dest, src)
Collections.copy(new ArrayList(), new ArrayList
Collections.copy(new ArrayList(), new ArrayList
Collections.copy(new ArrayList(), new ArrayList());
Collections.copy(new ArrayList(), new ArrayList
有兴趣的同学可以去看原文。