variance
原文没有怎么看懂,翻译过来就是形变,更抽象。variance和variant都是一个意思。
variance
定义了子类型和父类型的在进行一定操作后的结果之间的类型关系。
在面向对象语言中通常会有子类型(subtype)的概念,表示某类是某类的子类。
父类是可以引用子类类型对象的。
1 | A item = new B(); |
假设有A,B两个类,类B继承自类A,用≤
表示继承关系,即B≤A
。进行一定的变化操作后(通常是类型引用,数组,泛型),变化操作记作f(⋅)
如果
B≤A
,f(B)≤f(A)
,那么操作f(⋅)
就是covariance(协变)
如果
B≤A
,f(A)≤f(B)
,那么操作f(⋅)
就是contrvariance(逆变)
如果
B≤A
,f(A)
和f(B)
之间没有继承关系,那么操作f(⋅)
就是invariance(不变)
数组
1 | B[] b = new B[]{new B(), new B()}; |
Java 中父类的数组是可以持有子类的数组的,数组支持covarance
1 | val b: Array<B> = arrayOf(B()) |
Kotlin 中数组是不支持协变的
泛型
泛型在编译时期会检查类型,类型安全机制。
Java 中的泛型
1 | // 编译失败 |
两种方式都报错incompatiable type
,所以泛型是不支持covariance
,也不支持contrvariance
,是invariance
。
由于泛型默认情况是是invariance
,可以通过一定的方式让泛型支持contrvariance
以及covariance
。
Java 中支持协变的方式是extends
和super
关键字。
在泛型的传参处,申明泛型实参类型是受限制的边界类型,即 use-site variance。
1 | // covarance |
corvarince,只能获取元素,Producer Extends
contrvariance,只能保存元素,Consumer Super
declcration sit variance
这种方式只是限制类泛型类型的实参类型,只能A或A的子类作为泛型的参数。并不是什么申明处形变。
1 | static <T extends A> void printDeclaration(T r) { |
Kotlin 中的泛型
1 | val boxb: Box<B> = Box<B>() |
泛型默认是不支持协变的,是invariance
Kotlin 中支持协变的方式是in
和out
关键字。在定义泛型类型类或泛型方法的时候申明支持哪种形变,即Declaration-site variance
covariance,只能读取元素并作为返回类型,out
contravariance,只能保存元素并作为输入类型,in
covariance use out
out
标记的泛型,不能出现在参数中
1 | interface Producer<out T> { |
contravariance use in
in
标记的泛型不能出现在返回值中。
1 | interface Consumer<in T> { |
use-site variance
1 | interface Group<T> { |
跟 Java 中通配符泛型(generic wildcards)类似,语法上跟简洁了一些。
函数返回值的协变
在重载一个方法时返回类型是可以返回一个更小的范围,可以返回父类返回类型的子类,意即返回值支持协变,corvariance
。
1 | public class A { |