0%

Kotlin泛型的上界与下界

Kotlin 的泛型系统支持定义上界和下界约束,包括协变和逆变。这些特性使得 Kotlin 的泛型类型系统更加灵活和强大。下面是对 Kotlin 泛型上界和下界的详细说明:

泛型的上界 (Upper Bounds)

上界用于限制泛型类型参数的类型范围。默认情况下,泛型类型参数具有一个隐式的上界 Any?。你可以通过显式声明上界来进一步限制类型参数的类型范围。

示例

  1. 默认隐式上界

    1
    class Box<T>(val value: T)  // T 的隐式上界是 Any?
  2. 显式上界

    1
    class Box<T : Number>(val value: T)  // T 的上界是 Number,因此只能接受 Number 的子类型
  3. 多重上界: 如果需要使用多个上界,可以使用 where 子句来进行声明。

    1
    2
    3
    4
    5
    6
    fun <T> ensureAllNonNull(vararg args: T) where T : Any, T : Comparable<T> {
    for (arg in args) {
    checkNotNull(arg)
    println(arg)
    }
    }

泛型的下界 (Lower Bounds)

Kotlin 不直接提供显式声明下界的语法,但下界的概念可以通过协变和逆变来实现。协变和逆变是用于描述类型参数之间的子类型关系的概念,它们定义了类型参数在子类型化关系中的行为。

协变 (Covariance)

协变允许使用子类型来替代泛型类或接口的类型参数。在 Kotlin 中,协变使用关键字 out 来定义,表示泛型类型参数只能出现在输出位置(返回类型),不能出现在输入位置(函数参数)。

1
2
3
4
5
6
7
interface Source<out T> {
fun nextT(): T
}

fun demo(source: Source<String>) {
val anySource: Source<Any> = source // 协变,String 是 Any 的子类型,所以 Source<String> 可以赋值给 Source<Any>
}

逆变 (Contravariance)

逆变允许使用超类型来替代泛型类或接口的类型参数。在 Kotlin 中,逆变使用关键字 in 来定义,表示泛型类型参数只能出现在输入位置(函数参数),不能出现在输出位置(返回类型)。

1
2
3
4
5
6
7
interface Consumer<in T> {
fun consume(item: T)
}

fun demo(consumer: Consumer<Number>) {
val intConsumer: Consumer<Int> = consumer // 逆变,Int 是 Number 的子类型,所以 Consumer<Number> 可以赋值给 Consumer<Int>
}

使用示例

以下是一个综合示例如 Box 类和函数如何利用泛型的上界和协变逆变:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 定义一个具有上界的泛型类
class Box<T : Number>(val value: T)

fun <T : Number> sum(value1: T, value2: T): Double {
return value1.toDouble() + value2.toDouble()
}

// 定义一个协变接口
interface Source<out T> {
fun nextT(): T
}

// 定义一个逆变接口
interface Consumer<in T> {
fun consume(item: T)
}

fun main() {
// 使用具有上界的泛型类
val intBox = Box(1)
val doubleBox = Box(1.0)

println(sum(1, 2)) // 输出: 3.0
println(sum(1.0, 2.0)) // 输出: 3.0

// 示例协变
val stringSource: Source<String> = object : Source<String> {
override fun nextT(): String {
return "Hello"
}
}
val anySource: Source<Any> = stringSource
println(anySource.nextT()) // 输出: Hello

// 示例逆变
val numberConsumer: Consumer<Number> = object : Consumer<Number> {
override fun consume(item: Number) {
println("Consumed $item")
}
}
val intConsumer: Consumer<Int> = numberConsumer
intConsumer.consume(10) // 输出: Consumed 10
}

总结

  • 上界:限制泛型类型参数的类型范围,默认是 Any?,可以显式地使用 :<类型> 来指定。
  • 下界:Kotlin 没有直接的下界语法,但可以通过协变(out)和逆变(in)来实现特定的行为。
  • 协变:使用 out 关键字表示,只能用于返回类型,允许将子类型泛型对象赋值给超类型的变量。
  • 逆变:使用 in 关键字表示,只能用于输入类型,允许将超类型泛型对象赋值给子类型的变量。