先来看一个错误:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
error 1:
IntelliJ says:
- 1
- 1
The compiler says:
- 1
- 2
- 3
- 1
- 2
- 3
error 2:
IntelliJ gives me
- 1
- 1
Whereas the compiler just says
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
PECS法则
在看完下面简短的PECS后,再去思考思考上面的问题。
我们知道Java泛型可以有多种写法,主要是 extends 和 super 关键字。比如:
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
主要涉及的是Java泛型中重要的PECS法则:
? extends
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
存入数据:
-
fruits是一个Fruit子类的List,由于Apple是Fruit的子类,因此将apples赋给fruits是合法的。
-
编译器会阻止将Strawberry类加入fruits。在向fruits中添加元素时,编译器会检查类型是否符合要求。因为编译器只知道fruits是Fruit某个子类的List,但并不知道这个子类具体是什么类,为了类型安全,只好阻止向其中加入任何子类。
-
那么可不可以加入Fruit呢?很遗憾,也不可以。事实上,不能往一个使用了
? extends
的数据结构里写入任何的值。
疑问:向fruits中添加元素要检查类型,由于不知道具体的子类,编译报错。但为什么apples使用“=”赋给fruits就可以??应该由于不知道具体子类,也会编译报错才对啊
读取数据
但是,由于编译器知道它总是Fruit的子类型,因此我们总可以从中读取出Fruit对象:
- 1
- 1
? super
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
存入数据:
-
fruits是一个Apple超类(父类,superclass)的List。
-
出于对类型安全的考虑,我们可以加入Apple对象或者其任何子类(如RedApple)对象(因为编译器会自动向上转型),但由于编译器并不知道List的内容究竟是Apple的哪个超类,因此不允许加入特定的任何超类型。
读取数据
编译器在不知道是什么类型的情况下只能返回Object对象,因为Object是任何Java类的最终祖先类。
- 1
- 1
PECS原则总结
从上述两方面的分析,总结PECS原则如下:
- 如果要从集合中读取类型T的数据,并且不能写入,可以使用 ? extends 通配符;(Producer Extends)
- 如果要从集合中写入类型T的数据,并且不需要读取,可以使用 ? super 通配符;(Consumer Super)
- 如果既要存又要取,那么就不要使用任何通配符。
现在再去思考最开始的问题,应该会更清楚一点.
=========================
转自:http://blog.csdn.net/xx326664162/article/details/52175283