美文网首页
16.Kotlin星投影与泛型约束详解

16.Kotlin星投影与泛型约束详解

作者: leofight | 来源:发表于2018-02-26 22:04 被阅读0次

星投影

star projection(星投影)

Star<out T>:如果T的上界是TUpper,那么Star<*>就相当于Star<out T>,这表示当T的类型未知时,你可以Star<*>当中安全地读取TUpper类型的值。

Star<in T>:Star<*>就相当于Star<in Nothing>,这表示你无法向其中写入任何值。

Star<T>,如果T的上界为TUpper,那么Star<*>就相当于读取时的Star<out TUpper>以及写入时的Star<in Nothing>

如果泛型类型具有多个类型参数,则每个类型参数都可以单独投影。 例如,如果类型被声明为interface Function <in T, out U>,我们可以想象以下星投影:

Function<*, String>表示 Function<in Nothing, String>
Function<Int, *> 表示Function<Int, out Any?>
Function<*, *> 表示 Function<in Nothing, out Any?>

注意:星投影非常像 Java 的原始类型,但是安全。

示例代码

class Start<out T> {

}

class Star2<in T> {
    fun setValue(t: T) {

    }
}

class Star3<T>(private var t: T) {
    fun setValue(t: T) {

    }

    fun getValue(): T {
        return this.t
    }
}

fun main(args: Array<String>) {
    val star: Start<Number> = Start<Int>()
    val star2: Start<*> = star

    val star3: Star2<Int> = Star2<Number>()
    val star4: Star2<*> = star3

    //star4.setValue(3) //compile error

    val star5: Star3<String> = Star3<String>("hello")
    val star6: Star3<*> = star5

    star6.getValue()
    //star6.setValue("") //compile error

    val list: MutableList<*> = mutableListOf("hello", "world", "hello world")
    println(list[0])

    //list[0] = "test" //compile error
}

泛型擦除

Kotlin 为泛型声明用法执行的类型安全检测仅在编译期进行。 运行时泛型类型的实例不保留关于其类型实参的任何信息。 其类型信息称为被擦除。例如,Foo<Bar> 与 Foo<Baz?> 的实例都会被擦除为 Foo<*>。

示例代码

package com.leofight.kotlin2

class MyStorage<out T>(private var t: T) {

    fun getValue(): T {
        return this.t
    }

    fun setValue(t: @UnsafeVariance T) {
        this.t = t
    }
}

fun main(args: Array<String>) {
    var myStorage1: MyStorage<Int> = MyStorage(5)
    val myStorage2: MyStorage<Any> = myStorage1

    println(myStorage2.getValue())

    myStorage2.setValue("hello")//泛型擦除

    println(myStorage2.getValue())
}

泛型函数

不仅类可以有类型参数。函数也可以有。类型参数要放在函数名称之前:

fun <T> getValue(item: T): T {
    return item
}

要调用泛型函数,在调用处函数名之后指定类型参数即可:

fun main(args: Array<String>) {
    val item = getValue<Int>(3)
    println(item)

    val item2 = getValue("hello")
    println(item2)
}

泛型约束

能够替换给定类型参数的所有可能类型的集合可以由泛型约束限制。

上界

最常见的约束类型是与 Java 的 extends 关键字对应的 上界:

fun <T : Comparable<T>> sort(list: List<T>) {
    // ……
}

冒号之后指定的类型是上界:只有 Comparable<T> 的子类型可以替代 T。 例如:

sort(listOf(1, 2, 3)) // OK。Int 是 Comparable<Int> 的子类型
sort(listOf(HashMap<Int, String>())) // 错误:HashMap<Int, String> 不是 Comparable<HashMap<Int, String>> 的子类型

默认的上界(如果没有声明)是 Any?。在尖括号中只能指定一个上界。 如果同一类型参数需要多个上界,我们需要一个单独的 where-子句:

fun <T> copyWhenGreater(list: List<T>, threshold: T): List<String>
    where T : CharSequence,
          T : Comparable<T> {
    return list.filter { it > threshold }.map { it.toString() }
}

相关文章

网友评论

      本文标题:16.Kotlin星投影与泛型约束详解

      本文链接:https://www.haomeiwen.com/subject/bjjuxftx.html