Java泛型下――万恶的擦除(四)

2014-11-23 22:59:11 · 作者: · 浏览: 2
0 // We know that it returns at least Fruit:
11 Fruit f = flist.get(0);
12 }
13 } ///:~
复制代码
我们这里使用了通配符< extends Fruit>,可以理解为:具有任何从Fruit继承的类型的列表。我们会发现不仅仅是Orange对象不允许放入List,这时候极端的连Apple都不允许我们放入这个List中。这说明了一个问题List是不能像数组那样拥有协变性。
这里为什么会出现这样的情况,通过查看ArrayList的 源码我们会发现:当我们声明ArrayList< extends Fruit>中的add()的参数也变成了" extends Fruit",这时候编译器无法知道你具体要添加的是Fruit的哪个具体子类型,那么它就会不接受任何类型的Fruit。
但是这里我们发现我们能够正常的get()出一个元素的,很好理解,因为我们声明的类型参数是< extends Fruit>,编译器肯定可以安全的将元素返回,应为我知道放在List中的一定是一个Fruit,那么返回就好。
逆变:
上面我们发现get方法是可以的,那么当我们想用set方法或者add方法的时候怎么办?就可以使用逆变即超类型通配符。如下:
复制代码
1 public class SuperTypeWildcards {
2 static void writeTo(List< super Apple> apples) {
3 apples.add(new Apple());
4 apples.add(new Jonathan());
5 // apples.add(new Fruit()); // Error
6 }
7 } ///:~
复制代码
这里< super Apple>意即这个List存放的是Apple的某种基类型,那么我将Apple或其子类型放入到这个List中肯定是安全的。
总结一下:
< super T>逆变指明泛型类持有T的基类,则T肯定可以放入
< extends T>指明泛型类持有T的导出类,则返回值一定可作为T的协变类型返回
说了这么多,总结了一堆也发现了 Java泛型真的很渣,不好用,对程序员的要求会更高一些,一不小心就会出错。这也就是我们使用类库中的泛化类时常看到各种各样的警告的原因了。。。