java泛型中的PECS

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

 

总结

  1. 如果你想从一个数据类型里获取数据(List#get()),使用 ? extends 通配符
  2. 如果你想把对象写入一个数据结构里(LIst#add()),使用 ? super 通配符
  3. 如果你既想存,又想取,那就别用通配符。

 

举个栗子

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

猜你喜欢

转载自shifulong.iteye.com/blog/2252032