Kotlin泛型

作者: 漆先生 | 来源:发表于2021-03-30 15:48 被阅读0次

一、泛型

Kotlin 中的类也可以有类型参数:

class Box<T>(t: T) {
    var value = t
}

val box1: Box<Int> = Box(1)

//类型参数可以推断出来,例如从构造函数的参数或者从其他途径,允许省略类型参数:
val box2 = Box(1)

二、型变

声明处型变(declaration-site variance)与类型投影(type projections)。

1.java通配符

  • 上边界通配限定符,让 Collection<? extends Object>是 Collection<String>的超类
  • 下边界通配限定符,让List<? super String> 是 List<Object> 的⼀个超类

2.声明处型变

声明处型变:在类型参数声明处提供。这与 Java 的使用处型变相反。
out 修饰符:标注 Source 的类型参数 T 来确保它仅从 Source<T> 成员中返回(生产),并从不被消费。

interface Source<out T> {
    fun nextT(): T
}

fun demo(strs: Source<String>) {
    val objects: Source<Any> = strs // 这个没问题,因为 T 是⼀个 out-参数
}

in修饰符:它使得⼀个类型参数逆变:只可以被消费而不可以被生产。逆变类型的⼀个很好的例子是 Comparable :

interface Comparable<in T> {
    operator fun compareTo(other: T): Int
}

fun demo(x: Comparable<Number>) {
    x.compareTo(1.0)                // 1.0 拥有类型 Double,它是 Number 的⼦类型
    val y: Comparable<Double> = x   // 因此,我们可以将 x 赋给类型为 Comparable <Double> 的变量 
}

三、类型投影

1.使用处型变:类型投影

val ints: Array<Int> = arrayOf(1, 2, 3) 
val any = Array<Any>(3) { "" } 
copy(ints, any)

fun copy(from: Array<out Any>, to: Array<Any>) { …… }

类型投影: from 不仅仅是⼀个数组,而是⼀个受限制的(投影的)数组,只可以调用返回类型为类型参数 T 的方法,如上,这意味着我们只能调用 get() 。这就是我们的使用处型变的用法, 并且是对应于 Java 的 Array<? extends Object> ,但使用更简单些的方式。
in 投影⼀个类型:

fun fill(dest: Array<in String>, value: String) { …… }

Array<in String> 对应于 Java 的 Array<? super String> ,也就是说,你可以传递⼀个 CharSequence 数组或⼀个 Object 数组给 fill() 函数。

2.星投影

对类型参数一无所知,但仍然希望以安全的方式使用它。定义泛型类型的投影,该泛型类型的每个具体实例化将是该投影的子类型。 Kotlin 星投影语法:

  • 对于 Foo <out T : TUpper> ,其中 T 是⼀个具有上界 TUpper 的协变类型参数,Foo <> 等价于 Foo <out TUpper> 。这意味着当 T 未知时,你可以安全地从 Foo <> 读取 TUpper 的值。
  • 对于 Foo <in T> ,其中 T 是⼀个逆变类型参数,Foo <> 等价于 Foo <in Nothing> 。这意味着当 T 未知时,没有什么可以以安全的⽅式写⼊ Foo <> 。
  • 对于 Foo <T : TUpper> ,其中 T 是⼀个具有上界 TUpper 的不型变类型参数,Foo<*> 对于读取值 时等价于 Foo<out TUpper> ⽽对于写值时等价于 Foo<in Nothing>
    果泛型类型具有多个类型参数,则每个类型参数都可以单独投影:
  • Function<*, String> 表示 Function<in Nothing, String>
  • Function<Int, *> 表示 Function<Int, out Any?>
  • Function<*, *> 表示 Function<in Nothing, out Any?> 。

四、泛型函数

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

fun <T> singletonList(item: T): List<T> ?{
    // ……
}

fun <T> T.basicToString(): String { // 扩展函数
    // ……
}

五、泛型约束

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

1.上界

约束类型是与 Java 的 extends 关键字对应的 上界,冒号之后指定的类型是上界:只有 Comparable<T> 的⼦类型可以替代 T

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

默认的上界(如果没有声明)是 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() }
}

六、类型擦除

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

相关文章

  • 泛型

    与Java泛型相同,Kotlin同样提供了泛型支持。对于简单的泛型类、泛型函数的定义,Kotlin 与 Java ...

  • Kotlin---泛型

    Kotlin不变型泛型 Kotlin的不变型泛型和Java一样,通过声明泛型类型来使用泛型类。而该种泛型声明后,则...

  • Kotlin 泛型 VS Java 泛型

    建议先阅读我的上一篇文章 -- Java 泛型 和 Java 泛型一样,Kotlin 泛型也是 Kotlin 语言...

  • Kotlin for android学习六:泛型

    前言 kotlin官网和kotlin教程学习教程的笔记。 1. 声明泛型 2. 泛型约束 : 对泛型的类型上限进行...

  • 泛型

    Kotlin 泛型详解 声明一个泛型类 声明一个泛型方法 泛型约束 List 和 List 是...

  • Kotlin 泛型

    Kotlin 支持泛型, 语法和 Java 类似。例如,泛型类: 泛型函数: 类型变异 Java 的泛型中,最难理...

  • Kotlin:泛型杂谈(下)

    在Kotlin:泛型杂谈(上)中,从泛型扩展属性、非空约束、实例化类型参数三个方面简单介绍了一下Kotlin中泛型...

  • 【Android】 Kotlin(七)泛型

    深入理解Kotlin泛型 Kotlin 的泛型与 Java 一样,都是一种语法糖,即只在源代码中有泛型定义,到了c...

  • Kotlin 泛型

    说起 kotlin 的泛型,就离不开 java 的泛型,首先来看下 java 的泛型,当然比较熟悉 java 泛型...

  • Kotlin 泛型

    Kotlin 泛型 1. 泛型类 定义一个泛型类 使用 在继承中 使用 2. 泛型函数 使用 3. 泛型的擦除 无...

网友评论

    本文标题:Kotlin泛型

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