一、<? extends …>

extends指上界通配符,示例中指的是所有Fruit类及其派生的子类。
在这里插入图片描述
对该通配符指示的容器进行写入操作(set),就像收到一个包裹,上面写了包裹里都是水果,但编译器并不事先知道具体是哪一种水果,如果里面是香蕉,但放入了一个苹果就会造成错误,所以编译器禁止这种操作。

public void Func( List <? extends Fruit> temp) 
{
  temp.set(...); //compile time error
}

而对该通配符指示的容器进行读取操作(get),就像从包裹里拿一个水果,传递给一个Fruit对象。编译器无需关心到底是什么水果,因为Fruit类一定是该水果的超类,用Fruit对象调用的方法一定是该水果定义了的,不会发生错误。

二、super

super指下界通配符,示例中指的是所有Fruit类及其超类。
在这里插入图片描述

对该通配符容器进行读取(get)操作,就像收到一个包裹,里面是水果或者食物,但编译器不知道到底是什么,如果拿出一个并传递给一个Fruit对象,就有可能发生"超类对象被子类引用调用一个不存在的方法",造成错误。

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的子类,编译器无需直到容器具体的类型,就可以保证容器不会“调用一个不存在的方法”

三、总结

总结起来,编译器检查,如果可以确保总是用超类变量引用其子类对象,那么之后通过该变量调用的方法,一定在子类中已被定义。
而一旦出现用子类变量引用超类对象的情况,尽管其后也许并不一定发生错误,但编译器无法确定这一点,只能触发编译错误。

摘自:
作者:BJChangAn
链接:https://www.jianshu.com/p/447e13647824
来源:简书

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐