协变和逆变

注:以下均个人见解,如有错误,欢迎指出。

泛型的协变和逆变


概念解释

泛型的协变和逆变的作用举个栗子来说就是:协变,类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>

最后

泛型的协变和逆变大体可以用下图表示:
协变和逆变
现在描述的协变和逆变还不够详细,仅仅是概念上的,等真正用到的时候再详细补充。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值