zl程序教程

您现在的位置是:首页 >  Java

当前栏目

kotlin--泛型

2023-04-18 12:32:31 时间

kotlin作为一种高级语言,也提供了泛型,它的泛型比Java更为灵活

一、泛型类

1.定义泛型类

定义泛型类和Java差不多

class Magic<T>(_item: T) {
    var subOject: T = _item
}

data class Boy(var name: String, var age: Int)

data class Dog(var age: Int)

fun main() {
    println(Magic(Boy("danny", 15)).subOject)
    println(Magic(Dog(15)).subOject)
}

结果: Boy(name=danny, age=15) Dog(age=15)

二、泛型函数

1.泛型参数也可以用于函数
class Magic<T>(_item: T) {
    var subOject: T = _item
    var available: Boolean = false

    fun getItem(): T? {
        //available为true,返回泛型类型对象subOject
        return subOject.takeIf { available }
    }
}

data class Boy(var name: String, var age: Int)

fun main() {
    val magic = Magic(Boy("danny", 15))
    magic.available = true
    println(magic.getItem())
}
2.多个泛型参数的函数
class Magic<T>(_item: T) {
    var subOject: T = _item
    var available: Boolean = false

    fun <R> getItem(funp: (T) -> R): R? {
        //available为true,返回泛型类型对象R
        return funp(subOject).takeIf { available }
    }
}

data class Boy(var name: String, var age: Int)

data class Man(var name: String, var age: Int)

fun main() {
    val magic = Magic(Boy("danny", 15))
    magic.available = true
    //boy变成man
    val man = magic.getItem {
        Man(it.name, it.age.plus(10))
    }
    println(man)
}

三、泛型类型约束

1.如果想要对传递的泛型作约束,可以指定泛型的父类
//指定父类
class Magic<T : Human>(_item: T) {
    var subOject: T = _item
    var available: Boolean = false
}

open class Human(var age: Int)
2.如果想要放入多个实例,使用vararg关键字
class Magic<T : Human>(vararg _items: T) {
    var subOject: Array<out T> = _items
    var available: Boolean = false
}
3.使用[]操作符取值,也可以自己重载get函数
class Magic<T : Human>(vararg _items: T) {
    var subOject: Array<out T> = _items
    var available: Boolean = false

    fun <R> getItem(index: Int, funp: (T) -> R): R? {
        if (index > subOject.size - 1) return null

        //available为true,返回泛型类型对象R
        return funp(subOject[index]).takeIf { available }
    }

    operator fun get(index: Int): T? {
        return subOject[index].takeIf { available }
    }
}

//父类
open class Human(var age: Int)

class Boy(var name: String, _age: Int) : Human(_age)

class Man(var name: String, _age: Int) : Human(_age)

fun main() {
    val magic = Magic(Boy("danny", 15))
    magic.available = true
    //boy变成man
    val man = magic.getItem(0) {
        Man(it.name, it.age.plus(10))
    }
    println("${man?.name} ${man?.age}")
}
4.out

out修饰泛型,表示该泛型对象可以赋值给父类

class Product<out T : Human>(val product: T) {
    fun getItem(): T? = product
}

//父类
open class Human(var age: Int)

class Boy(var name: String, _age: Int) : Human(_age)

class Man(var name: String, _age: Int) : Human(_age)

fun main() {
    //泛型是Human,传入的是Boy,Human的子类
    val boy: Product<Human> = Product(Boy("danny", 15))
    println(boy.getItem())
}

结果: com.aruba.mykotlinapplication.Boy@3cd1a2f1

5.in

in修饰泛型,表示该泛型对象可以赋值给子类

class Consume<in T : Human>() {
    fun cousume(item: T) {
        println(item)
    }
}

//父类
open class Human(var age: Int)

open class Boy(var name: String, _age: Int) : Human(_age)

class Man(_name: String, _age: Int) : Boy(_name, _age)

fun main() {
    //泛型为Boy类型
    val man: Consume<Boy> = Consume()
    //传入的是Boy的父类Man
    man.cousume(Man("danny", 15))
}

结果: com.aruba.mykotlinapplication.Man@3cd1a2f1

而Java中泛型只能使用对应的泛型,没有继承关系

6.reified

kotlin也不允许对泛型作类型检查,当我们想要知道泛型参数具体是哪个类型时,可以使用reified关键字修饰 reified必须和inline配合使用,原因是编译的时候,编译器就需要知道我们传入的类型,只不过代码写成了泛型而已

class Magic {
    inline fun <reified T : Human> getBoy(backUp: () -> T): T {
        //随机取一个
        val human = listOf(
            Boy("danny", 15),
            Man("jack", 25)
        ).shuffled().first()

        println(human)
        //如果和backup函数返回参数的类型相同,直接返回
        return if (human is T) {
            human
        } else {//否则返回backup函数调用结果
            backUp()
        }
    }
}

open class Human()

class Boy(var name: String, var age: Int) : Human()

class Man(var name: String, var age: Int) : Human()

fun main() {
    val magic = Magic()
    println(magic.getBoy { Boy("danny", 15) })
}

随机到不是Boy型变量的结果: com.aruba.mykotlinapplication.Man@3f99bd52 com.aruba.mykotlinapplication.Boy@4f023edb 随机到Boy型变量的结果: com.aruba.mykotlinapplication.Boy@3f99bd52 com.aruba.mykotlinapplication.Boy@3f99bd52