Java中<? super T>和List<? extends T>的区别
<? extends T>
下面通配符声明List<? extends Number> foo3
的赋值式是合法的:
List<? extends Number> foo3 = new ArrayList<Number>(); // Number "extends" Number (in this context)
List<? extends Number> foo3 = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>(); // Double extends Number
- 读 - 上面给出可能的赋值式,你能确保从
List foo3
读取什么类型的对象?:- 你可以读取一个
Number
,因为任意包含一个Number
或一个Number
子类的列表都可赋值于foo3
。 - 你不可读取一个
Integer
,因为foo3
可以指List<Double>
。 - 你不可读取一个
Double
,因为foo3
可以指List<Integer>
。
- 你可以读取一个
- 写 - 上面给出可能的赋值式,你能添加什么类型的对象至
List foo3
?:- 你不能添加一个
Integer
,因为foo3
可以指List<Double>
。 - 你不能添加一个
Double
,因为foo3
可以指List<Integer>
。 - 你不能添加一个
Number
,因为foo3
可以指List<Integer>
。
- 你不能添加一个
你不能将任何对象添加到List<? extends T>
是因为你不能保证它真正指向的是哪种类型的列表,因此,你不能保证某对象在该列表中是允许的。唯一的“确保”是你只能从中读取,你会得到一个T或者T的子类。
<? super T>
下面通配符声明List<? super Number> foo3
的赋值式是合法的:
List<? super Integer> foo3 = new ArrayList<Integer>(); // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList<Number>(); // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList<Object>(); // Object is a superclass of Integer
- 读 - 上面给出可能的赋值式,你能确保从
List foo3
读取什么类型的对象?:- 你不能确保读取一个
Integer
,因为foo3
可以指List<Number>
或List<Object>
。 - 你不能确保读取一个
Number
,因为foo3
可以指List<Object>
。 - 唯一能确定的是你能读取一个
Object
或Object
子类的对象(但是你不知道具体哪个子类)。
- 你不能确保读取一个
- 写 - 上面给出可能的赋值式,你能添加什么类型的对象至
List foo3
?:- 你可以添加一个
Integer
或Integer
的子类。 - 你不能添加一个
Number
,因为foo3
可以指List<Integer>
。 - 你不能添加一个
Object
,因为foo3
可以指List<Integer>
。
- 你可以添加一个
PECS
记住PECS: “Producer Extends, Consumer Super”。
- "Producer Extends" - 如果你需要一个
List
来生产T
值(你想从列表读取T
),你就用? extends T
来声明它,如List<? extends Integer>
。但是你不能够添加东西到列表中。 - "Consumer Super" - 如果你需要一个
List
来消费T
值(你想从列表写入T
),你就用? super T
来声明它,如List<? super Integer>
。但是你能从列表读取什么类型对象是不能确定的。 - 如果你要列表读写兼顾,你就不要任何通配符声明该列表,如
List<Integer>
。
我的助记
- PECS -> PE teacher taught me computer science.
- extends du, super xie -> edsx -> 恶毒的思想
一个例子
public class Collections { public static <T> void copy(List<? super T> dest, List<? extends T> src) {for (int i = 0; i < src.size(); i++) dest.set(i, src.get(i)); }
}
关于该例更多说明。
参考资料
Difference between <? super T> and <? extends T> in Java