Kotlin基础 泛型

一.泛型类

1.定义

        泛型类的构造函数可以接受任何类型。

                 //    泛型
class MagicBox<T>(item : T) {
    var available =false;
    private var subject:T =item  

}

class Box(val name:String,val age:Int)
class Man(val name:String,val age:Int)
fun main() {
    val box1:MagicBox<Box> = MagicBox(Box("小华", 20))
    val box2:MagicBox<Man> = MagicBox(Man("小华", 10))
  
}

MagicBox类指定地泛型参数由放在一对<>里的字母T表示,T是个代表item类型的占位符。MagicBox类接受任何类型的item作为主构造函数值(item :T),并将item值赋给同样是T类型的subject私有属性。

二.泛型函数

1.泛型函数

        泛型参数也可以用于函数。

class MagicBox<T>(item : T) {
    var available =false;
    private var subject:T =item
 

    fun fetch():T?{
        return subject.takeIf { available }
    }

}

class Box(val name:String,val age:Int)
class Man(val name:String,val age:Int)
fun main() {
    val magicBox = MagicBox(Box("小华", 20))

    magicBox.available=true
    //打印
     magicBox.fetch()?.run { 
        println("you find $name")
    }
}

        

2.多泛型函数

        泛型函数或泛型类也可以有多个泛型参数。

class MagicBox<T>(item : T) {
    var available =false;
    private var subject:T =item
  

    fun fetch():T?{
        return subject.takeIf { available }
    }
     //这里新传进了一个类把通过构造函数传进来的带替了
    fun <R> fetch(SubjectModFunction:(T)->R) :R?{
        return SubjectModFunction(subject).takeIf { available }
    }

}

fun main() {
    val magicBox = MagicBox(Box("小华", 20))
    
    magicBox.available=true
   //这里传了一个lambda表达式用于传值
    val fetch = magicBox.fetch {
        Man("小华", 30)
    }
    fetch?.let {
        print("${it.name}   ${it.age}")
    }
}

三.泛型类型约束

1.泛型类型约束

        如果要确保MagicBox里面只能装指定类型的物品,如Human类型,怎么办?

class MagicBox<T: Human>(item : T) {
    var available =false;
    private var subject:T =item
    
  
    fun fetch():T?{
        return subject.takeIf { available }
    }
    
}
fun main() {
    val magicBox:MagicBox<Human> = MagicBox(Box("小华", 20))

 
}

2.vararg关键字与get函数

        MagicBox能存放任何类型的Human实列,但一次只能放一个,如果需要放入多个实例需要用vararg关键字

class ArrayMagicBox<T:Human>(vararg item : T) {
    var available =false;

    //集合泛型
     private var subject: Array<out T> =item

    fun fetch(index : Int ): T? {
        return subject[index].takeIf { available }
    }
     //这里和之前哪个一样用法只是加了个下标要从数组取值
    fun <R> fetch(index:Int, SubjectModFunction:(T)->R) :R?{
        return SubjectModFunction(subject[index]).takeIf { available }
    }

}

3.[ ]操作符取值

            想要通过[ ]操作符取值,可以重载运算符函数get方法。

class ArrayMagicBox<T:Human>(vararg item : T) {
    var available =false;
    //集合泛型
     private var subject: Array<out T> =item
    
    //通过对象调用get方法获取指定下标值
    operator fun get(index: Int):T?=subject[index].takeIf { available }
    
    fun fetch(index : Int ): T? {
        return subject[index].takeIf { available }
    }
    //这里和之前哪个一样用法只是加了个下标要从数组取值
    fun <R> fetch(index:Int, SubjectModFunction:(T)->R) :R?{
        return SubjectModFunction(subject[index]).takeIf { available }
    }

}

4.out

        out(协变),如果泛型类只将泛型类型作为函数的返回(输出),那么使用out,可以称之为生产类/接口,因为它主要是用来生产(produce)指定的泛型对象。

interface Production<out T>{
    fun product():T
}

5.in

        in(逆变),如果泛型类只将泛型类型作为函数的入参(输入),那么使用in,可以称之为消费者/接口,因为它主要是用来消费(consume)指定的泛型对象。

interface Consumer<in T>{
    fun consume(item : T)
}

6.为什么使用in&out

        父类泛型对象可以赋值给子类泛型对象,用in

        子类泛型对象可以复制给父类泛型对象,用out

7.invariant

        如果泛型类既将泛型类型作为函数参数,又将泛型类型作为函数的输出,那么既不用out也不用in

interface ProductionConsumer< T>{
    fun consume(item : T)
    fun product():T
}

8.reified

        有时候,你可能想知道某个泛型参数具体什么类型,reified关键字能帮你检查泛型参数类型。Kotlin不允许对泛型参数T做类型检查,因为泛型参数类型会被类型擦除,也就是说,T的类型信息在运行时是不可知的。

class MagicBoxReified<T:Human> (){


    //内联          泛型类型推断
    inline fun <reified T> randomOrBackup(backup:()->T):T{
        val item= listOf(
            Boy("小华",20),
            Mna("小刚",24)

        )

        val last = item.shuffled().last()
        return if (last is T){
            last
        }else{
            backup()
        }
    }
}


open class Human(val age:Int){

}

class Boy(val name:String,age: Int): Human(age){
    override fun toString(): String {
        return "$name     $age"
    }
}


class Mna(val name:String,age: Int):Human(age){
    override fun toString(): String {
        return "\n  $name     $age"
    }
}



fun main() {
    val magicBoxReified = MagicBoxReified<Human>()
    val randomOrBackup = magicBoxReified.randomOrBackup {
        Mna("小红", 30)
    }
    print(randomOrBackup)
}

下一篇: Kotlin基础 扩展

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值