Kotlin泛型

  1. 定义泛型类
  2. 泛型函数
  3. 泛型类型约束
  4. vararg关键字与get函数
  5. out协变
  6. in逆变
  7. invariant不变
  8. reified

1.定义泛型类

泛型类的构造函数可以接受任意类型
泛型参数由放在一对<>里的字母T表示
class Magic <T>(item : T){
    private var subject :T = item
}

class Boy(val name : String,val age : Int)

class Dog(val weight:Int)

fun main() {
    val magic1 : Magic<Boy> = Magic(Boy("Jack", 18))
    val magic2 : Magic<Dog> = Magic(Dog(20))
}

2.泛型函数

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

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

class Boy2(val name : String,val age : Int)

class Dog2(val weight:Int)

fun main() {
    val magic1 : Magic2<Boy2> = Magic2(Boy2("Jack", 18))
    magic1.apply {
        available = true
    }.fetch()?.run {
        println("you find $name")
    }
}

3.多泛型参数

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

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

    //把一个Boy变成Man
    //返回类型也是泛型
    fun <R> fetch(subjectModFunction : (T) -> R) : R?{
        return subjectModFunction(subject).takeIf { available }
    }
}

class Boy3(val name : String, val age : Int)

class Man(val name : String, val age : Int)

fun main() {
    val magic1 : Magic3<Boy3> = Magic3(Boy3("Jack", 18))
    magic1.apply {
        available = true
    }.fetch {
        Man(it.name,it.age.plus(20))
    }?.run {
        println("$name , $age")
    }
}

3.泛型类型约束

class Magic4 <T : Human>(item : T){
    var available = false
    private var subject :T = item

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

    //把一个Boy变成Man
    //返回类型也是泛型
    fun <R> fetch(subjectModFunction : (T) -> R) : R?{
        return subjectModFunction(subject).takeIf { available }
    }
}

open class Human(val age : Int)

class Boy4(val name : String, age : Int) : Human(age)

class Man2(val name : String,age : Int) : Human(age)



fun main() {
    val magic1 : Magic4<Boy4> = Magic4(Boy4("Jack", 18))
    magic1.apply {
        available = true
    }.fetch {
        Man2(it.name,it.age.plus(20))
    }?.run {
        println("$name , $age")
    }
    
}

4.vararg关键字与get函数

传多个相同参数

class Magic5 <T : Human2>(vararg item : T){
    var available = false
    //out关键字            泛型数组
    private var subject :Array<out T> = item

    fun fetch(index : Int) : T?{
        return subject[index].takeIf { available }
    }

    //把一个Boy变成Man
    //返回类型也是泛型
    fun <R> fetch(index : Int,subjectModFunction : (T) -> R) : R?{
        return subjectModFunction(subject[index]).takeIf { available }
    }
}

open class Human2(val age : Int)

class Boy5(val name : String, age : Int) : Human2(age)

class Man3(val name : String, age : Int) : Human2(age)



fun main() {
    val magic1 : Magic5<Boy5> = Magic5(Boy5("Jack", 18),Boy5("Ross", 18))
    magic1.apply {
        available = true
    }.fetch(1) {
        Man3(it.name,it.age.plus(20))
    }?.run {
        println("$name , $age")
    }

}
重载get运算符
    operator fun get(index: Int): T?{
        return subject[index].takeIf { available }
    }
    //就可以通过这样取值
    magic1[1]

5.out协变

如果泛型类只将泛型类型作为函数的返回,那么使用out
可以称之位生产类、生产接口,因为它主要是用来生产指定的泛型对象
子类泛型对象可以赋值给父类泛型对象

6.in逆变

如果泛型类只将泛型类型作为函数的入参,那么使用In
可以称之为消费者类、消费者接口,因为它主要是用来消费指定的泛型对象
父类泛型对象可以赋值给子类泛型对象

7.invariant不变

如果泛型类即将泛型类型作为函数参数,又作为函数输出
那么即不使用In也不使用out

为什么使用in&out

提高函数的扩展性	-> 多态
out只返回泛型	->	为了支持返回所有泛型	->	所有子类可以赋值给父类
in只接收泛型	->	为了支持接收所有泛型	->	所有父类可以赋值给子类

在这里插入图片描述

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

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

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

open class Food

open class FastFood : Food()

class Burger : FastFood()

//生产者

//食品商店
class FoodStore : Production<Food>{
    override fun product(): Food {
        println("FoodStore product")
        return Food()
    }
}
//快餐商店
class FastFoodStore : Production<FastFood>{
    override fun product(): FastFood {
        println("FastFoodStore product")
        return FastFood()
    }
}

//汉堡商店
class BurgerStore : Production<Burger>{
    override fun product(): Burger {
        println("BurgerStore product")
        return Burger()
    }
}

//消费者
class EveryBody : Comsumer<Food>{
    override fun consume(item: Food) {
        println("EveryBody consume(")
    }
}

class ModernPeople : Comsumer<FastFood>{
    override fun consume(item: FastFood) {
        println("ModernPeople consume(")
    }
}

class AmericanPeople : Comsumer<Burger>{
    override fun consume(item: Burger) {
        println("AmericanPeople consume(")
    }
}

fun main() {
    //赋值
    val production1 : Production<Food> = FoodStore()
    //java里不行 kotlin可以  ->  是因为有out关键字  ->  子类泛型对象可以赋值给父类泛型对象   ->实际上是子类对象
    val production2 : Production<Food> = FastFoodStore()
    production2.product()
    println(production2 is Food)        //false
    println(production2 is FastFood)    //false
    println(production2 is FastFoodStore)//true
    //父类泛型对象可以赋值给子类泛型对象 ->  in关键字   ->  实际类型是父类对象
    val consumer1 : Comsumer<Burger> = EveryBody()
    val consumer2 : Comsumer<Burger> = ModernPeople()
    val consumer3 : Comsumer<Burger> = AmericanPeople()
}

9.reified

有时候可能想知道某个泛型参数具体是什么类型,reified关键字可以帮助检查、
泛型参数的类型,Kotlin不允许对泛型参数做类型检查,因为泛型参数类型会被擦除
也就是说,T的类型信息在运行时是不可知的
class Magic5 <T : Human2>(){
//   fun <T> randomOrBackup(backup: () -> T) : T{
//       val items = listOf(
//           Boy5("Jack",20),
//           Man3("John",40)
//       )
//
//       val random = items.shuffled().first()
//       //random is T 报错,在运行期间是不可知的
//       return if(random is T){
//           random
//       }else{
//           backup()
//       }
//   }

    inline fun <reified T> randomOrBackup(backup: () -> T) : T{
       val items = listOf(
           Boy5("Jack",20),
           Man3("John",40)
       )

       val random = items.shuffled().first()
       //保留类型
       return if(random is T){
           random
       }else{
           backup()
       }
   }
}

open class Human2(val age : Int)
class Boy5(val name : String, age : Int) : Human2(age)
class Man3(val name : String, age : Int) : Human2(age)

fun main() {
    val box1 : Magic5<Human2> = Magic5()
    val subject = box1.randomOrBackup {
        Man3("Jimmy",38)
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值