前置知识: Kotlin

Kotlin类型系统

00:00
2 min Advanced 2026/6/14

泛型、型变与星投影

概述

Kotlin 的类型系统在 Java 泛型基础上引入了声明型变(declaration-site variance),使泛型 API 更安全、更易用。理解协变逆变和星投影设计质量泛型接口的前提。

基础概念

型变三种形式

型变关键字角色说明
协变out生产者只能读取,不能写入
逆变in消费者只能写入,不能读取
不变两者兼有既能读又能写,无子类型关系

子类型关系

// 协变:Producer<String> 是 Producer<Any> 的子类型
interface Source<out T> { fun next(): T }
val stringSource: Source<String> = ...
val anySource: Source<Any> = stringSource // 合法

// 逆变:Consumer<Any> 是 Consumer<String> 的子类型
interface Sink<in T> { fun put(value: T) }
val anySink: Sink<Any> = ...
val stringSink: Sink<String> = anySink // 合法

// 不变:MutableStack<String> 不是 MutableStack<Any> 的子类型
class MutableStack<T> {
    fun push(item: T) {}
    fun pop(): T = TODO()
}

快速上手

协变(out)

// 协变:T 只能出现在返回位置
interface Repository<out T> {
    fun getAll(): List<T>
    fun findById(id: String): T
}

// 可以安全地将 Repository<String> 赋值给 Repository<Any>
val userRepo: Repository<User> = UserRepository()
val anyRepo: Repository<Any> = userRepo // 合法

// 错误:out 位置不能有 T 类型的参数
// interface Repository<out T> {
//     fun save(item: T) // 编译错误!T 在 in 位置
// }

逆变(in)

// 逆变:T 只能出现在参数位置
interface Comparator<in T> {
    fun compare(a: T, b: T): Int
}

// 可以安全地将 Comparator<Any> 赋值给 Comparator<String>
val anyComparator: Comparator<Any> = ...
val stringComparator: Comparator<String> = anyComparator // 合法

// 错误:in 位置不能返回 T
// interface Comparator<in T> {
//     fun get(): T // 编译错误!T 在 out 位置
// }

星投影

// 星投影:不知道或不在乎类型参数时使用
fun printSize(list: List<*>) {
    println(list.size) // 可以,不依赖 T
    // list.get(0) 返回 Any?
}

// 星投影的规则
// 对于 Source<out T>,Source<*> 等价于 Source<out Any?>
// 对于 Sink<in T>,Sink<*> 等价于 Sink<in Nothing>
// 对于 MutableStack<T>(不变),Stack<*> 读取按 Any?,写入按 Nothing

// 使用场景:类型参数不重要
fun dump(map: Map<*, *>) {
    map.forEach { (k, v) -> println("$k = $v") }
}

详细用法

泛型约束

// 上界约束:T 必须是 Comparable 的子类型
fun <T : Comparable<T>> maxOf(a: T, b: T): T = if (a > b) a else b

// 多重约束:使用 where 子句
fun <T> copyWhenGreater(source: List<T>, threshold: T): List<T>
    where T : Comparable<T>, T : CharSequence {
    return source.filter { it > threshold }
}

// 泛型约束与型变结合
interface SortedSet<out T : Comparable<T>> {
    fun first(): T
    fun last(): T
}

具体化类型参数(reified)

// 普通泛型在运行时被擦除,无法检查类型
// inline + reified 保留类型信息
inline fun <reified T> isType(value: Any): Boolean {
    return value is T // 运行时可以检查 T 的类型
}

// 常见用途:简化 Gson/Jackson 反序列化
inline fun <reified T> Gson.fromJson(json: String): T {
    return fromJson(json, object : TypeToken<T>() {}.type)
}

// 使用
val user: User = gson.fromJson(jsonString)
val users: List<User> = gson.fromJson(jsonArray)

泛型函数与扩展

// 泛型扩展函数
fun <T> List<T>.second(): T = this[1]

// 带型变的泛型扩展
fun <T> Iterable<T>.filterInstanceOf<R>(): List<R> {
    return filterIsInstance<R>()
}

// 使用处型变(use-site variance)
fun <T> copy(from: Array<out T>, to: Array<in T>) {
    for (i in from.indices) {
        to[i] = from[i]
    }
}

常见场景

类型安全的构建器

// 利用泛型和 Lambda 构建类型安全的 DSL
class Table<T> {
    private val rows = mutableListOf<T>()

    fun row(item: T) {
        rows.add(item)
    }

    fun build(): List<T> = rows.toList()
}

fun <T> table(block: Table<T>.() -> Unit): List<T> {
    return Table<T>().apply(block).build()
}

// 使用
val users = table<User> {
    row(User("张三", 25))
    row(User("李四", 30))
}

泛型 Repository 模式

// 协变的只读 Repository
interface ReadOnlyRepository<out T> {
    fun findById(id: String): T
    fun findAll(): List<T>
}

// 逆变的写操作
interface WriteRepository<in T> {
    fun save(item: T)
    fun delete(item: T)
}

// 完整的 Repository 组合
interface Repository<T> : ReadOnlyRepository<T>, WriteRepository<T>

注意事项

  • 协变(out)的类型参数只能出现在返回位置,逆变(in)只能出现在参数位置
  • Kotlin 的声明型变比 Java 的使用处型变安全、更简洁
  • 投影不能写入(除了 Nothing,即不能写入任何
  • reified 只能与 inline 函数一起使用
  • 泛型运行时被擦除,reified唯一保留类型信息的方式
  • 数组协变的(Java 遗留设计),集合是不变的(更安全

进阶用法

递归泛型约束

// 递归类型约束:枚举实现 Comparable
inline fun <reified T : Enum<T>> enumValueOfOrNull(name: String): T? {
    return try {
        enumValueOf<T>(name)
    } catch (e: IllegalArgumentException) {
        null
    }
}

// 自引用泛型(CRTP 模式)
interface Comparable<Self : Comparable<Self>> {
    fun compareTo(other: Self): Int
}

型变与集合操作

// 理解集合操作的型变
fun processItems(items: List<out Any>) {
    // 可以安全读取
    for (item in items) {
        println(item)
    }
    // 不能添加元素(编译错误)
    // items.add("new") // 错误
}

// 利用协变实现灵活的 API
fun <T : Any> merge(
    source1: List<out T>,
    source2: List<out T>
): List<T> {
    return source1 + source2
}

// 可以合并不同子类型
val result = merge(listOf(Dog(), Cat()), listOf(Animal()))

知识检测

学习进度

-- 已学文档
--% 知识覆盖率

学习推荐

专注模式