存在对象及容器两个问题
1,对象类型的子类型,比如:苹果是不是水果的子类型?
2,容器类型的子类型,比如:一盒苹果是不是一盒水果的子类型?
子类型问题的根源在于继承
子类继承基类后,子类除了拥有基类的一切外,子类还有自己仅有的部分属性
举例:苹果继承了水果,苹果拥有水果的所有属性,但还有自己的属性,比如苹果的酸甜
子类型问题具体表现在指针与对象的匹配上
1,一个自声明的指针:我是一个指向苹果的指针
2,一个被指向的对象,比如一个水果或一个苹果
指针的称职
1,一个自声明为水果的指针指向一个苹果,该指针称职,从该指针你一定可以取回一个水果
2,一个自声明为苹果的指针指向一个水果,该指针不称职,从该指针你不一定能取回一个苹果,你只能取回一个水果,甚至其可能是一根香蕉
总结:一个苹果可以赋给一个自声明为水果的指针,但反之不行,会导致该指针不称职
以List容器为例
List<Apple>表示一盒苹果,也即容器中存在若干指针,这些指针自声明指向苹果
List<Fruit>表示一盒水果,也即容器中存在若干指针,这些指针自声明指向水果
容器可以的操作
写入:
List<Fruit>可以写入水果对象,也即容器中的指针可以指向水果对象
List<Fruit>也可以写入苹果对象,因为容器中自声明指向水果的指针也可以指向苹果
List<Apple>不可以写入水果对象,因为容器中指针自声明为苹果,如果挂入水果则少了苹果的特性
读出:
List<Apple>可以读出苹果对象,也即从容器中指针可以读出苹果对象
List<Apple>也可以读出水果对象,毕竟苹果对象中包含一个水果对象
List<Fruit>不可以读出苹果对象,因为容器中指针指向水果,该水果可能缺乏苹果的属性
List<Fruit>与List<Apple>的子类型关系
从容器写入考察
List<Fruit>可以写入Fruit及Apple,List<Apple>可以写入Apple
可见List<Fruit>比List<Apple>写入更多
从容器读出考察
List<Fruit>可以读出Fruit,List<Apple>可以读出Apple及Fruit
可见List<Apple>比List<Fruit>读出更多
可见从容器特性上没有谁能包含谁,也即相互之间都没有子类型关系
List<? Super Apple>:
这个容器里面指针槽的指针是<? Super Apple>,也即苹果或水果,或更上层的“可食用植物”
根据指针,这个容器总可以添加苹果,红苹果,烟台红苹果
根据指针,除Object之外,不敢保证能完整地读出什么,甚至不能保证读出“可食用植物”,因为指针类型可能是“植物”
相对于List<Apple>限制了读
List<? Extends Apple>:
这个容器里面指针槽的指针是<? Extends Apple>,也即苹果或红苹果
根据指针,这个容器不能写入任何对象,因为指针类型可能是“烟台红苹果”,除非我们写入“烟台市xxx果园的红苹果”
根据指针,这个容器总可以读出苹果或水果,或更上层的“可食用植物”
相对于List<Apple>限制了写
List<? extends Apple> 是 List<? extends Fruit> 的子类型
因为前者不仅可以读出Fruit,还可以读出Apple,在写方面是两者都不可写
由于 Apple 本身是 Fruit 的子类型,而容器也是如此对应关系,所以这里是 型变
型变:如果 aa 是 a 的子类型,同时 Holder<aa> 也是 Holder<a>的子类型
List<? super Fruit> 是 List<? super Apple> 的子类型
因为前者不仅可以写入Apple,还可以写入 Fruit
由于 Apple 本身是 Fruit 的子类型,而容器的子类型关系相反,所以这里是 逆变
逆变:如果 aa 是 a 的子类型,同时 Holder<a> 是 Holder<aa>的子类型
通配符容器之间存在子类型关系,其根源在于通配符限制了容器的读或写