1. extends
extends指上界通配符,示例中指的是所有Fruit类及其派生的子类。
对该通配符指示的容器进行写入操作(set),就像收到一个包裹,上面写了包裹里都是水果,但编译器并不事先知道具体是哪一种水果,如果里面是香蕉,但放入了一个苹果就会造成错误,所以编译器禁止这种操作。
/*example*/
public void Func( List <? extends Fruit> temp)
{
temp.set(...); //compile time error
}
而对该通配符指示的容器进行读取操作(get),就像从包裹里拿一个水果,传递给一个Fruit对象。编译器无需关心到底是什么水果,因为Fruit类一定是该水果的超类,用Fruit对象调用的方法一定是该水果定义了的,不会发生错误。
2. super
super指下界通配符,示例中指的是所有Fruit类及其超类。
对该通配符容器进行读取(get)操作,就像收到一个包裹,里面是水果或者食物,但编译器不知道到底是什么,如果拿出一个并传递给一个Fruit对象,就有可能发生
"超类对象被子类引用调用一个不存在的方法"
,造成错误。
/*example*/
public void Func( List <? super Fruit> temp)
{
Fruit a = temp.get(); //compile time error .
//if not so,assume return an Food obj, refered by a Fruit variable,it seems to be ok
//a.Fruitcolor(); // Food obj don't have a method defined in Fruit class, oop!
}
而对其进行写入(set)操作,就像向包裹中放入东西,只要保证放入的东西是Fruit的子类,编译器无需直到容器具体的类型,就可以保证容器不会“调用一个不存在的方法”
3. 总结
总结起来,编译器检查,如果可以确保总是用超类变量
引用其子类对象
,那么之后通过该变量调用的方法,一定在子类中已被定义。
而一旦出现用子类变量
引用超类对象
的情况,尽管其后也许并不一定发生错误,但编译器无法确定这一点,只能触发编译错误。