泛型

Quibbler 2020-6-14 960

泛型


        类型参数化,和Java一样,Kotlin也有泛型。省去类型强转的麻烦,也提供了类型安全方面的保障。

        


1、泛型类

        定义带泛型参数的类。

例:

class Type<T>(type: T) {
    var type: T = type
        get() {
            return field
        }
        set(value) {
            field = value
        }
}

        泛型类Type中的值就会根据实际传入的参数类型

    var bool = Type(false)
    println(bool.type.javaClass.simpleName)
    var str = Type("string")
    println(str.type.javaClass.simpleName)
    var num: Type<Int> = Type(1)
    println(num.type.javaClass.simpleName)

        输出结果:

    //boolean
    //String
    //int


注意:

        ①如果已经将某个变量初始化为一种泛型,就不能再次赋值成其它类型的泛型了:

        ②创建泛型类型的对象直接使用var关键字即可,Kotlin自动进行类型推断。如果一定要指定变量的类型,必须也要指定泛型的类型:

        正确的泛型类型定义语法,加上具体的泛型类型:

var num: Type<Int> = Type(1)



2、泛型方法

        方法的参数、返回值也可以是泛型,更加传入参数的值推断实际类型。

例:

        定义一个泛型方法:

fun <T> whichType(type: T) {
    if (type is String) {
        println("String")
    } else if (type is Int) {
        println("Int")
    } else if (type is Boolean) {
        println(type)
    }
}

        传入不同类型的参数,泛型函数根据传入的参数做不同的操作:

    whichType(1)
    whichType(false)
    whichType("what?")
    /**
     * 输出:
     * Int
     * false
     * String
     */


        上面一堆判空方法,能不能简写呢?比如直接简写成:

fun <T> whichType(type: T) {
    println(type.javaClass.simpleName)
}

         这是不行的,非空才能调用泛型参数的方法

        既然需要判空?,判空语法参考《 Kotlin基本语法》,就可以根据传入的参数类型做不同的操作:

fun <T> whichType(type: T) {
    println(type?.javaClass?.simpleName)
}

        虽然不会提示错误。但是,实际编译运行却会报错:

Error:Kotlin: Type inference failed: Not enough information to infer parameter T in val <T : Any!> Class<T>.simpleName: String!

Please specify it explicitly.

Error:Kotlin: Type parameter bound for T in val <T : Any> T.javaClass: Class<T>

 is not satisfied: inferred type T is not a subtype of Any

        提示意思是没有足够的信息推断类型T。



3、泛型限定

        上面的问题可以很轻松的用泛型限定来解决:

fun <T : Any> whichType(type: T) {
    println(type.javaClass.simpleName)
}


        但是这样泛型方法传入的泛型又不可以为null

        在泛型限定T前加上,表明该泛型参数可能为null

fun <T : Any?> whichType(type: T) {
    //type可为null
}

        看着似乎完美了,是因为还是空方法,加上点调用又警告了和上一节出现一样的情况,因为默认的上界是 Any?,加不加都一样。

        那有没有办法呢?还是有的用?:表达式做判空断处理

fun <T : Any?> whichType(type: T) {
    println((type ?: 1).javaClass.simpleName)
}



4、协变

        Java泛型中有通配符,这里不详细介绍,参考《java泛型通配符详解》

    <T extends View> void painting(T t) {
        //T可以是所有继承自View的子类
    }


4.1、声明处型变 out

        out 使得一个类型参数协变,协变类型参数只能用作输出,可以作为返回值类型但是无法作为入参的类型。

例:

class Variance<out T>(val t: T) {
    fun variance(): T {
        return t
    }
}

        协变返回

    var a = Variance<String>("String")
    var b = Variance<Any>("Any")
    //可以将a赋值给b,返回类型将协变成为a中的泛型类型String
    b = a


4.2、类型投影 in

        in 使得一个类型参数逆变,逆变类型参数只能用作输入,可以作为入参的类型但是无法作为返回值的类型。

例:

class Projections<in T>( t: T) {
    fun projections() {
    }
}

        输入协变

    var a = Projections<String>("String")
    var b = Projections<Any>("Any")
    a = b

        

注意:

        inout不能同时使用,两者是互斥的

        协变输入只能由泛型宽的转到泛型窄的,反过来不行。



学习资料:

        Kotlin 泛型


不忘初心的阿甘
最新回复 (0)
    • 安卓笔记本
      2
        登录 注册 QQ
返回
仅供学习交流,切勿用于商业用途。如有错误欢迎指出:fluent0418@gmail.com