kotlin泛型、以及in、out关键字的作用

作者声明:本文仅作为作者学习期间个人理解所发布的内容,不周误笔之处,希望各位读者能在评论区加以斧正,以此促进共同进步。

泛型的定义:        

          无论是在类、还是在方法中,<T>泛型占位符的定义都只表示这个类/方法支持泛型,并不是表示这个类/方法的返回值和属性都被定义为泛型。也就是说即是使用<T>修饰,你同样可以使用基本类型作为属性和返回值。

//最简单的泛型类格式
class Creature<T>{}

//泛型类支持泛型属性
class Creature<T>(var gender:T){}

//还可以支持泛型方法
class Creature<T>(var gender:T){
    
    fun <T>speak(){
        //方法体
    }

    
    //支持泛型参数的方法
    fun <T>speak(name:T){
        //方法体
    }


    //返回泛型的方法
    fun <T>speak(name:T):T{
        //方法体
    }

    //多泛型,此处只做入门讲解,多泛型不做深入
    fun <R,T>speak(name:T,age:R):R{
        //方法体
    }
    

}

泛型的实现示例:

class Man<T>(var name:T){
    
    fun <T>speak(pre :T){
        println("$pre $name")
    }
}

fun main() {
    /*<String>表示这个泛型类/方法具体实现时使用的类型,
        由于该类/方法支持泛型,
        如果你将泛型类限定为String,那么传递的参数和属性也应该使用String类型
        同样你可以使用任何你想用的类型。
        此处的<String>可以省略,因为kotlin有自动类型推断
        当你传递对应类型参数之后,该类/方法的类型就会被默认为你传递的参数类型
    */

    var man=Man<String>("张三")
    //var man=Man("张三")
    man.speak<String>("我是")
}

泛型关键字in、out的作用

在kotlin中in代表代表逆变,对应java中的? super class;

out代表协变,对应java中的? extends class。


为什么要使用这两个关键字?

当我们定义泛型类或泛型方法时class P<T>{...}

如果我们想对这个泛型做具体实现,比如创建一个对象var p=p<Any>()

那么再遇到需要该类型的方法时fun consume(p:P<Any>()),他可以作为参数传递;

但是作为Any的子类String,使用string实现泛型var p1=p<String>()

p1却不能直接作为consume方法的参数,需要先类型转换为p1=P<Any>()

为了保证这种转换过程中的安全,所以kotlin使用in、out来保证兼容性

in关键字的使用和实现:

只需要记住:

        in修饰的泛型,在做具体实现时,可以使用期望类的父类来实现,并且泛型参数只能用在输入位置,即属性、方法参数

        out修饰的泛型在做具体实现时,可以使用期望类的子类来实现,并且泛型参数只能用在输出位置,即方法的返回值

//定义三个类用于验证转换关系,继承关系Creature->People->Man
open class Creature (var name:String){
}

open class People(name: String) : Creature(name) {
}

class Man(name: String) :People(name){
}

//接收泛型的消费者类
class Consumer<in T>{
    //使用in表示期望子类实现时,可以用其父类实现替代
    fun consume(item:T){
        if (item is Creature){
            println(item.name)
        }
    }
}

//定义一个消费方法,接受People中间类作为泛型实现
fun process(con:Consumer<People>){
    con.consume(People("张三"))
}

fun main() {
    //期望子类,使用父类实现
    var creature=Consumer<Creature>()
    process(creature)
}
out关键字的引用和实现
//沿用上面三个继承类
class OnlyRead<out T>{
    //out修饰的泛型需要只能作为输出参数,为了输出一个T泛型参数定义一个可空item
    val item:T?=null
    fun speak():T?{
        println("only read speak")
        return item
    }
}

fun entry(on:OnlyRead<People>){
    on.speak()
}


fun main() {
    var man=OnlyRead<Man>()
    entry(man)
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值