变型
描述了拥有相同基础类型和不同类型类型实参的泛型类型之间是如何关联;
比如 List
协变
Kotlin 中的 List 接口表示的都是 只读 集合。如果A是B的子类型,那么List 就是 List的子类型。
这样的类火灾接口被称为协变的,就说 子类型化被保留了。协变类的前提是他必须是一个 泛型类。、
用关键字out来声明 类型参数T为协变:
子类型化会被保留(Producer
是Producer 的子类型) T只能在out位置
out位置表示 生产类型
in位置表示 消费类型
List和MutableList协变不同举例:
注意有个特例就是 构造方法的参数既不在 in位置 也不在 out位置。即使类型参数声明成了 out,也可在构造函数的声明中使用:
逆变
可以看出是协变的镜像:对一个逆变来说,他的子类化关系与用作类型实参的类的子类型化关系是相反的。即在 in位置 使用T,接口只是消费类型为T的值
一个类可以在一个类型参数上协变,同时在另外一个类型参数上逆变。Function接口就是例子
使用点变型
在类声明的时候就能够指定 变型修饰符,因为这些修饰符会应用到所有类被使用的地方-称为声明点变型。雷士用java的通配符类型(? extentds 和 ? super)。 在每一次使用类型参数的类型的时候,指定这个类型参数是否可以用它的子类型或者超类型替换,这就是使用点变型。
在Kotlin中提供了一个更优雅的方式:
如上source只用到了out位置的获取数据情况,因此定义为out,就不能执行添加数据的相关操作,因为添加数据是 destination 在此函数中才执行的操作。
可以为类型声明中类型参数任意的用法指定变型修饰符,包括形参类型,局部变量类型,函数返回类型等,这就成为 类型投影
如果类型参数已经有out类型,获取他的out投影就没有意义。比如List
星号投影
星号投影用来表示你不知道关于泛型参数的任何信息。语法很简单,只能用在对泛型类型实参不感兴趣的地方:只是使用生产值,而不关心类型。
注意MutableList<>和Mutable