Kotlin学习(六)之-- 对协变out与逆变in的理解和使用(对比Java)

/**
 * 1泛型Animal 是Father的父类,Son1的父类的父类
 * 2泛型Father 是Animal的子类,Son1的父类
 * 3泛型Son1 是Father的子类
 */
open class Animal(var name :String){
    
    }
open class Father(name : String) : Animal(name){
    
    }
     class Son1(name: String):Father(name){
    
    }

一. 协变out
1.1

/** 协变 out*/
interface GetClass<out T>{
    
    
    /*** 错误写法*/
//    fun get(pargma:T) : T //out只用去读取,因此不可以做参数去修改,但可以作为返回值去接收
    /**正确写法*/
    fun get() : T
}

1.2

/**
 * out相当于Java的<? extends xx>
 */

class GetClassImp1 : GetClass<Animal> {
    
    
    override fun get(): Animal {
    
    
        return Animal("Animal")
    }
}

class GetClassImp2 : GetClass<Father>{
    
    
    override fun get(): Father {
    
    
        return Father("Father")
    }
}

class GetClassImp3 : GetClass<Son1>{
    
    
    override fun get(): Son1 {
    
    
        return Son1("Son1")
    }
}
    //out:相当于java的<? extends T>,可以接收T和T的子类
    //协变 相当于父类可以接收子类
    var g1 : GetClass<Animal> = GetClassImp1()
    var g2 : GetClass<Father> = GetClassImp2()
    //var g3 : GetClass<Father> = GetClassImp1()//错误写法 声明泛型Father 不可以接收具体泛型 Animal(子类不可以接收父类)
    println(g1.get().name)

Java例子:

        List<CharSequence> list = new ArrayList <String>(); //错误写法
        List<? extends CharSequence> list1 = new ArrayList<String>();//正确写法

二. 逆变 in
1.1

/** 逆变 in*/
interface SetClass<in T>{
    
    
    /**错误写法*/
//    fun set(name:String) : T //in只用去修改, 因此不可以作为返回值去接受,但可以作为参数去获取然后修改
    /**正确写法*/
    fun set(pargma : T)

}
class SetClassImp1 : SetClass<Animal> {
    
    
    override fun set(pargma: Animal) {
    
    
    }
}

class SetClassImp2 : SetClass<Father> {
    
    
    override fun set(pargma: Father) {
    
    
    }
}

class SetClassImp3 : SetClass<Son1> {
    
    
    override fun set(pargma: Son1) {
    
    
    }
}

    var i1 : SetClass<Animal> = SetClassImp1()//正确写法
    var i2 : SetClass<Son1> = SetClassImp1()//正确写法,可以接收父类
    var i3 : SetClass<Animal> = SetClassImp2()//错误写法 声明泛型Animal 不可以接收具体泛型 Father(父类不可以接收子类)
    i1.set(Animal("Animal"))

对比Java

        List<String> list2 = new ArrayList<CharSequence>(); //错误写法
        List<? super char> list3 = new ArrayList<CharSequence>(); //正确写法

三.总结
协变out :
1.用于读取操作,得作为返回值,不可以作为参数,类比get()
2.声明泛型时,相当于Java的<? extends T>,可以接收T和T的子类
逆变in:
1.用与修改操作,得作为参数去进行修改,不可以作为返回值,类比set()
2.声明泛型时,相当于Java的<? super T>,可以接收T和T的父类

猜你喜欢

转载自blog.csdn.net/XJ200012/article/details/122576888