1. List<? extends T>和List<? super T>有哪些区别?
①List<? extends T> ,只允许泛型为T及T的子类引用调用。比如:
List<? extends Number> list = new ArrayList<Double>;
而List<? super T>,只允许泛型为T及T的父类引用调用。比如:
List< ? super Integer> list = new ArrayList<Number>;
②List<? extends T>,可以获取,不可以插入,比如说,
List<? extends Number> list = null;
list = new ArrayList<Integer>();
//√,取Number对象,赋给Number类型,当然符合Java规范
Number num1 = list.get(1);
//×,取Number对象,想赋给Integer类型,由于可能是Double类型、Float类型等等,自然就不符合Java规范
Integer num2 = list.get(1);
//×,new一个Integer对象,因为声明写着List<? extends Number>,不能确定实例化对象的具体类型,所以不能进行插入。
list.add(new Integer(1));
List<? super T>,则相反,可以插入,不可以获取,(因为Number是Integer的父类型,所以List<Number>是List<? super Integer>的子类型),比如说,
List<? super Interger> list = null;
list = new ArrayList<Number>();
//×,子类对象的引用无法赋值给兄弟类的引用
Number num1 = list.get(1);
//×,父类对象的引用无法赋值给子类的引用
Integer num2 = list.get(1);
//√,子类对象的引用可以赋值给父类对象的引用
list.add(new Integer(1));
2. 类名<? super T>存在哪些实际应用场景?
①PECS原则,由于<? extends T>的只能取,不能存,而<? super T>得只能存,不能取,因此就有producer用<? extends T>,consumer用<? super T>
注意:extends只出不进,属于生产者;super只进不出,属于消费者。这也就是“Producer Extends Consumer Super”。
②看底层源码,java.util.Collections.copy(List<? super T> dest, List<? extends T> src)也有应用。
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
int srcSize = src.size();
if (srcSize > dest.size())
throw new IndexOutOfBoundsException("Source does not fit in dest");
if (srcSize < COPY_THRESHOLD ||
(src instanceof RandomAccess && dest instanceof RandomAccess)) {
for (int i=0; i<srcSize; i++)
dest.set(i, src.get(i));
} else {
ListIterator<? super T> di=dest.listIterator();
ListIterator<? extends T> si=src.listIterator();
for (int i=0; i<srcSize; i++) {
di.next();
di.set(si.next());
}
}
}