美文网首页
Kotlin基础-泛型

Kotlin基础-泛型

作者: 独自闯天涯的码农 | 来源:发表于2023-04-10 15:17 被阅读0次

一、定义

泛型,即 "参数化类型",将类型参数化,可以用在类,接口,方法上。
与 Java 一样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼。
声明一个泛型类:

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

创建类的实例时我们需要指定类型参数:

val box: Box<Int> = Box<Int>(1)
// 或者
val box = Box(1) 
// 编译器会进行类型推断,1的类型Int,所以编译器知道我们说的是 Box<Int>
  • 定义泛型类型变量,可以完整地写明类型参数,如果编译器可以自动推定类型参数,也可以省略类型参数。
    Kotlin 泛型函数的声明与 Java 相同,类型参数要放在函数名的前面:
fun <T> boxIn(value: T) = Box(value)
  • 在调用泛型函数时,如果可以推断出类型参数,可以省略泛型参数

二、泛型约束

我们可以使用泛型约束来设定一个给定参数允许使用的类型。
Kotlin 中使用 : 对泛型的类型上限进行约束。
最常见的约束是上界(upper bound):

fun <T : Comparable<T>> sort(list: List<T>) {
    // ……
}
  • Comparable 的子类型可以替代 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 中没有通配符类型,它有两个其他的东西:

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

1、声明处型变

声明处的类型变异使用协变注解修饰符:in、out,消费者 in, 生产者 out。

  • 使用 out 使得一个类型参数协变,协变类型参数只能用作输出,可以作为返回值类型但是无法作为入参的类型:
  • in 使得一个类型参数逆变,逆变类型参数只能用作输入,可以作为入参的类型但是无法作为返回值的类型:
// 定义一个支持协变的类
class Runoob<out A>(val a: A) {
    fun foo(): A {
        return a
    }
}

fun main(args: Array<String>) {
    var strCo: Runoob<String> = Runoob("a")
    var anyCo: Runoob<Any> = Runoob<Any>("b")
    anyCo = strCo
    println(anyCo.foo())   // 输出 a
}

// 定义一个支持逆变的类
class Runoob<in A>(a: A) {
    fun foo(a: A) {
    }
}

fun main(args: Array<String>) {
    var strDCo = Runoob("a")
    var anyDCo = Runoob<Any>("b")
    strDCo = anyDCo
}

2、类型投影

有些时候, 你可能想表示你并不知道类型参数的任何信息, 但是仍然希望能够安全地使用它. 这里所谓"安全地使用"是指, 对泛型类型定义一个类型投射, 要求这个泛型类型的所有的实体实例, 都是这个投射的子类型。
对于这个问题, Kotlin 提供了一种语法, 称为 星号投射(star-projection):

  • 假如类型定义为 Foo<out T> , 其中 T 是一个协变的类型参数, 上界(upper bound)为 TUpper ,Foo<> 等价于 Foo<out TUpper> . 它表示, 当 T 未知时, 你可以安全地从 Foo<> 中 读取TUpper 类型的值.
  • 假如类型定义为 Foo<in T> , 其中 T 是一个反向协变的类型参数, Foo<> 等价于 Foo<inNothing> . 它表示, 当 T 未知时, 你不能安全地向 Foo<> 写入 任何东西.
  • 假如类型定义为 Foo<T> , 其中 T 是一个协变的类型参数, 上界(upper bound)为 TUpper , 对于读取值的场合, Foo<*> 等价于 Foo<out TUpper> , 对于写入值的场合, 等价于 Foo<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 的原生类型(raw type)非常类似, 但可以安全使用

相关文章

  • Kotlin 基础:泛型

    一、为什么要有泛型 效率、成本 减少样板代码的编写 二、泛型的分类 泛型类 泛型方法 三、泛型的关键字 3.1 T...

  • 泛型

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

  • Kotlin---泛型

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

  • Kotlin 泛型 VS Java 泛型

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

  • 第一天

    概述: Kotlin基础面向过程面向对象接口、扩展、泛型 为什么学习Kotlin 1.Google官方指定2.简介...

  • Kotlin for android学习六:泛型

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

  • Kotlin基础(9)-泛型

    前言 本文主要介绍一下Kotlin的泛型 Java中数组的设计问题 先看一下这个代码 在编译的时候编译器不会报错,...

  • 泛型

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

  • Kotlin 泛型

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

  • Kotlin:泛型杂谈(下)

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

网友评论

      本文标题:Kotlin基础-泛型

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