泛型的简单使用(二)- Kotlin 版

215 阅读2分钟

这是我参与更文挑战的第2天,活动详情查看: 更文挑战

泛型的简单使用(二)- Kotlin 版

同步代码地址 github.com/xyz0z0/Andr…

在 Kotlin 中使用泛型和 Java 中大致相同,比较 Kotlin 最好也是运行在 Jvm 上面的。但是源于 Kotlin 的一些特性,导致在使用泛型时也有一些不同点,下面就让我们一起看看都有哪些不同点吧。

类型参数约束写法不同

在 Java 中可以使用 extends 表示类型约束,在 Kotlin 中,则是使用 : 来区分。

    // Java 使用 extends
    public <T extends Number> int total(List<T> list){
        return 0;
    }
    // Kotlin 使用 :
    fun <T : Number> total(list: List<T>): Int {
        return 0
    }
类型参数为 Null 的处理

Kotlin 是空类型安全机制的,泛型中也是如此。如果定义泛型的时候使用的是 T ,那么在使用的时候是可以接收 null 值的,因为默认会将上界指定为 Any?。如果需要保证不接受可空类型的话,则需要使用 T : Any 方式来定义泛型。

    fun <T> testNull1(list: List<T>) {

    }

    fun <T : Any> testNull2(list: List<T>) {

    }

    fun test(){
        val list = emptyList<String>()
        testNull1<String?>(list)
        testNull2<String>(list)
    }
内联函数和实化

由于泛型擦除机制的存在,导致我们在使用泛型的过程中,是无法判断具体类型的。比如说判断一个类型是否是我们定义的泛型 T 就无法实现。不过 kotlin 中通过内联函数和实化就可以实现这个功能,当然这里面只是一个障眼法,其实内联函数在编译的时候,编译器就会把具体的函数调用替换成我们定义的内联方法。所以这时候我们的泛型类型也就确定下来了。当然这就导致我们无法在 Java 里面调用该方法了,而且在调用的时候传入的泛型就必须是一个具体类型了,而不应该是另一个泛型。

    // 这段代码是无法通过编译的,因为 T 无法用在下面的语句中
    fun <T> isInt(value: Int): Boolean {
        return value is T // error:Cannot check for instance of erased type: T
    }

    // 这段代码是可以用的,但是在调用的时候传入的必须是具体的类型。
    inline fun <reified T> isString(value: String): Boolean {
        return value is T
    }

    fun <S : Any> test2() {
        isString<String>("")
        isString<S>("") // error:Cannot use 'S' as reified type parameter. Use a class instead.
    }
   
星号投影

Kotlin 中 * 号对应于 Java 中的 ? 表示包含未知类型的元素。这种类型在使用的时候只可以获取值,而不可以设置值。

本文是个人的学习记录,不免对技术点有错误或不够深入的理解,还望大神小白批评指教。