extends
List<? extends Number>
下面这三种通配符声明都是合法的
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
Reading
- 能从foo3中读一个Number
- 不能从foo3中读一个Integer
- 不能从foo3中读一个Double
Writing
- 不能添加Number到foo3
- 不能添加Integer到foo3
- 不能添加Double到foo3
因为foo3可以指向任意Number的子类型list,只能保证从foo3中读出的是Number,不能确定foo3指向的是一个什么类型,所以add任意类型都会报错
super
List <? super T >
下面这三种通配符声明都是合法的
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
Reading
- 不能确定读出的是一个Integer,因为有可能指向List<Number> or List<Object>
- 不能确定读出的是一个Number,因为有可能指向List<Object>
- 只能读出Object,但无法确定这个Object是什么类型
Writing
- 能add Integer,
- 能add Integer的子类型
- 不能add Double
- 不能add Number
- 不能add Object
总结
- 如果你想从一个数据类型里获取数据(List#get()),使用 ? extends 通配符
- 如果你想把对象写入一个数据结构里(LIst#add()),使用 ? super 通配符
- 如果你既想存,又想取,那就别用通配符。
举个栗子
public static <T> void copy(List<? extends T> src, List<? super T> dest) { for (int i = 0; i < src.size(); i++) { dest.add(i, src.get(i)); } }
英文wiki
http://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java