注:以下均个人见解,如有错误,欢迎指出。
概念解释
泛型的协变和逆变的作用举个栗子来说就是:协变,类A是类B的父类,但是list<A>却不是list<B>的父类,当传入参数需要的是list<A>类型但实际给予的是list<B>类型时,就会产生报错;逆变,同理,类A是类B的父类,但是list<A>却不是list<B>的父类,当方法传入参数需要的是list<B>类型但实际给予的是list<A>类型时,就会产生报错。
协变
需要使用关键词out
来指定泛型支持协变,需要注意的是,泛型协变时,不能在其泛型类型的数据上进行赋值操作,否则会造成类型转换的安全隐患。但是可以在其构造函数的位置使用val关键字进行赋初值(val和private var都可以,只要保证泛型类型的数据不会被外部修改就行)
例如:
class MyClass<out T>(val value:T){
//doSomeThings
}
实际应用时:
open class ClassA {
open fun prl() {
println("classA")
}
}
class ClassB : ClassA() {
override fun prl() {
println("classB")
}
}
class MyClass<out T>(val value: T) {
//doSomeThings
}
fun test(v: MyClass<ClassA>) {
v.value.prl()
}
fun main() {
val a1 = ClassA()
val b1 = ClassB()
val aa = MyClass<ClassA>(a1)
val bb = MyClass<ClassB>(b1)
test(aa)
test(bb)
}
结果是:
classA
classB
这样,无论是MyClass<ClassA>
或者MyClass<ClassB>
,test方法都能够接收,而且这样的话,上面例子中class MyClass<out T>(val value:T)
中的value也不会被修改,不用担心类型转化的安全隐患。
逆变
逆变时,使用关键字in
来指定泛型支持逆变。
例如:
open class ClassA {
open fun prl() {
println("classA")
}
}
class ClassB : ClassA() {
override fun prl() {
println("classB")
}
}
interface MyClass<in T> {
fun prl(value: T)
}
fun test(v: MyClass<ClassB>) {
val value = ClassB()
v.prl(value)
}
fun main() {
val aa = object : MyClass<ClassA> {
override fun prl(value: ClassA) {
value.prl()
}
}
val bb = object : MyClass<ClassB> {
override fun prl(value: ClassB) {
value.prl()
}
}
test(aa)
test(bb)
}
结果是:
classB
classB
test()
原本只能够接收MyClass<ClassB>
,但是MyClass
经过逆变以后,使得MyClass<ClassB>
变成了MyClass<ClassA>
的父类型,所以也能够接收MyClass<ClassA>
。
最后
泛型的协变和逆变大体可以用下图表示:
现在描述的协变和逆变还不够详细,仅仅是概念上的,等真正用到的时候再详细补充。