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
- 运行时类型擦除