Kotlin 的 Generics

Kotlin 的 Generics(泛型)本质上是参数化类型(parametric polymorphism),用于在类型层面抽象算法或数据结构,使其具备类型安全(type safety)与复用性(reusability)。


一、基本语法

1️⃣ 泛型类

kotlin 复制代码
class Box<T>(val value: T)
  • T 是类型参数(type parameter)
  • 使用时指定具体类型:
kotlin 复制代码
val intBox = Box<Int>(10)
val strBox = Box<String>("hello")

2️⃣ 泛型函数

kotlin 复制代码
fun <T> printValue(value: T) {
    println(value)
}
  • <T> 写在函数名前
  • 调用时通常可以类型推断:
kotlin 复制代码
printValue(123)     // T = Int
printValue("abc")   // T = String

二、类型约束(Upper Bound)

泛型默认是 T : Any?

如果你想限制类型:

kotlin 复制代码
fun <T : Number> sum(a: T, b: T): Double {
    return a.toDouble() + b.toDouble()
}

这里表示:

复制代码
T 必须是 Number 或其子类

多重约束

kotlin 复制代码
fun <T> example(value: T)
where T : Number, T : Comparable<T> {
}

表示:

  • 必须是 Number
  • 必须可比较

三、变型(Variance)------核心重点

这是 Kotlin 泛型最关键的部分。

1️⃣ 不变(Invariant)

默认情况下:

kotlin 复制代码
class Box<T>

那么:

复制代码
Box<Int> ≠ Box<Number>

即使 Int 是 Number 的子类,也不能赋值。


2️⃣ 协变(Covariant)------ out

kotlin 复制代码
class Box<out T>(val value: T)

含义:

复制代码
Box<Int> 是 Box<Number> 的子类型

原则:

只读生产者(Producer)用 out

例子:

kotlin 复制代码
val intBox: Box<Int> = Box(10)
val numberBox: Box<Number> = intBox   // 合法

为什么安全?

因为它只能"输出"T,不能接收T。


协变的限制

kotlin 复制代码
class Box<out T>(val value: T) {
    fun setValue(value: T) { }  // ❌ 错误
}

因为如果允许写入,就可能破坏类型安全。


3️⃣ 逆变(Contravariant)------ in

kotlin 复制代码
interface Consumer<in T> {
    fun consume(item: T)
}

含义:

复制代码
Consumer<Number> 是 Consumer<Int> 的子类型

原则:

只写消费者(Consumer)用 in


4️⃣ 记忆口诀

Producer out

Consumer in

简称 PECS原则(和Java一样)


四、使用点变型(use-site variance)

Kotlin 支持:

kotlin 复制代码
fun copy(from: Array<out Any>, to: Array<Any>) { }

这里 out 是在使用时声明的。


五、星投影(Star Projection)

kotlin 复制代码
val list: List<*> = listOf(1, 2, 3)

等价于:

复制代码
List<out Any?>

你可以读,但读出来类型是 Any?

不能写入。


六、类型擦除(Type Erasure)

和 Java 一样:

泛型在运行时会被擦除

kotlin 复制代码
if (value is List<Int>) { }   // ❌ 编译错误

因为运行时不知道泛型参数。


七、reified ------ 解决类型擦除

Kotlin 的重大优势。

kotlin 复制代码
inline fun <reified T> isType(value: Any): Boolean {
    return value is T
}

必须:

  • inline
  • reified

使用:

kotlin 复制代码
isType<String>("abc")

这在 Java 是做不到的。


八、泛型 + 扩展函数

例如你之前问过:

kotlin 复制代码
fun <T> List<T>.second(): T {
    return this[1]
}

T 来自调用对象。


九、泛型与 sealed / enum 区别

你之前问过 sealed interface。

泛型是:

类型抽象

sealed 是:

类型层级封闭

两个解决的问题不同。


十、常见坑

1️⃣ MutableList 是不协变的

kotlin 复制代码
val ints: MutableList<Int> = mutableListOf(1,2)
val numbers: MutableList<Number> = ints   // ❌

因为可以写入。


2️⃣ List 是协变的

kotlin 复制代码
val ints: List<Int> = listOf(1,2)
val numbers: List<Number> = ints   // ✅

因为它是:

kotlin 复制代码
interface List<out E>

十一、本质理解

泛型本质是:

复制代码
在类型系统层面对算法进行抽象

而变型本质是:

复制代码
控制子类型关系在泛型中的传播方式

Kotlin 泛型 =

  • 编译期类型安全
  • 支持协变/逆变
  • 支持 reified
  • 运行时类型擦除
相关推荐
jinanwuhuaguo8 小时前
最新更新版本,OpenClaw v2026.4.2 深度解读剖析:Task Flow 重磅回归与安全架构的全面硬化
android·开发语言·人工智能·回归·kotlin·安全架构·openclaw
ForteScarlet1 天前
从 Kotlin 编译器 API 的变化开始: 2.3.20
android·开发语言·后端·ios·开源·kotlin
hnlgzb1 天前
请详细解释一下MVVM这个设计模型
android·kotlin·android jetpack·compose
夏沫琅琊1 天前
Kotlin 基础(一)
kotlin
夏沫琅琊1 天前
Android API 发送短信技术文档
android·kotlin
夏沫琅琊1 天前
Android 彩信导出技术文档
android·kotlin
hnlgzb2 天前
安卓app kotlin语法,Hilt是什么东西?
android·开发语言·kotlin
simplepeng2 天前
Kotlin 协程桥接(suspendCoroutine):将任意基于回调的 Android API 转换为挂起函数
kotlin