Kotlin 泛型
泛型是一种"参数化类型"的特性,允许在定义类、接口和方法时使用类型参数。
泛型基础
什么是泛型?
// 泛型类
class Box<T>(val value: T) {
fun get(): T = value
}
fun main() {
val intBox = Box(42) // Box<Int>
val stringBox = Box("Hello") // Box<String>
val anyBox = Box(Any()) // Box<Any>
println(intBox.get()) // 42
println(stringBox.get()) // Hello
}
为什么使用泛型?
- 类型安全:编译时检查类型错误
- 代码复用:一套代码处理多种类型
- 性能提升:无需装箱/拆箱
// 不使用泛型 - 类型不安全
class OldBox(val value: Any)
// 使用泛型 - 类型安全
class NewBox<T>(val value: T)
fun main() {
// 错误在编译时发现
val box: NewBox<String> = NewBox(123) // 编译错误!
}
泛型类
定义泛型类
class Container<T> {
private var item: T? = null
fun set(item: T) {
this.item = item
}
fun get(): T? = item
}
fun main() {
val intContainer = Container<Int>()
intContainer.set(42)
println(intContainer.get()) // 42
val stringContainer = Container<String>()
stringContainer.set("Hello")
println(stringContainer.get()) // Hello
}
多类型参数
class Pair<K, V>(val key: K, val value: V)
fun main() {
val pair = Pair("name", "Tom")
println("${pair.key} = ${pair.value}") // name = Tom
val pair2 = Pair(1, "one")
println("${pair2.key} = ${pair2.value}") // 1 = one
}
泛型函数
定义泛型函数
fun <T> identity(value: T): T = value
fun <T> printValue(value: T) {
println("Value: $value")
}
fun <T, R> transform(value: T, transform: (T) -> R): R {
return transform(value)
}
fun main() {
println(identity(42)) // 42
println(identity("Hello")) // Hello
printValue(100)
printValue("Kotlin")
println(transform(5) { it * 2 }) // 10
}
泛型扩展函数
fun <T> List<T>.secondOrNull(): T? {
return if (size >= 2) this[1] else null
}
fun <T : Number> List<T>.average(): Double {
return if (isEmpty()) 0.0 else sumOf { it.toDouble() } / size
}
fun main() {
val list = listOf("a", "b", "c")
println(list.secondOrNull()) // b
val nums = listOf(1, 2, 3)
println(nums.average()) // 2.0
}
类型约束
上界约束
// T 必须继承自 Number
class NumberBox<T : Number>(val value: T)
fun <T : Number> sum(a: T, b: T): Double {
return a.toDouble() + b.toDouble()
}
fun main() {
val box = NumberBox(42) // OK
// val box2 = NumberBox("42") // 编译错误!
println(sum(1, 2)) // 3.0
println(sum(1.5, 2.5)) // 4.0
}
多个约束
// T 必须实现 Comparable<T> 和 Serializable
class ComparableContainer<T> where T : Comparable<T>, T : java.io.Serializable
fun <T> demo(value: T) where T : Comparable<T>, T : java.io.Serializable {
// ...
}
多上界
// 需要特定类型时,使用具体类作为上界
fun <T> printNumber(item: T) where T : Number {
println("Number: ${item.toInt()}")
}
fun <T> printChar(item: T) where T : Char {
println("Char: $item")
}
泛型与可空性
可空类型参数
class NullableBox<T>(val value: T?)
fun main() {
val box = NullableBox<String>(null)
println(box.value) // null
// T? 允许传入可空类型
val box2: NullableBox<String?> = NullableBox(null)
}
* 星号投影
class Box<T>(var item: T)
fun main() {
val box: Box<*> = Box("Hello")
// item 类型变为 Any?
println(box.item) // Hello
// 无法写入具体类型
// box.item = 42 // 编译错误!
}
协变与逆变
协变 (out)
// Producer<T> - 只产出 T
// out T 允许 T 或 T 的子类
abstract class Producer<out T> {
abstract fun produce(): T
}
class Animal
class Dog : Animal()
class DogProducer : Producer<Dog>() {
override fun produce(): Dog = Dog()
}
fun main() {
// Producer<Dog> 可以赋值给 Producer<Animal>
val producer: Producer<Animal> = DogProducer()
}
逆变 (in)
// Consumer<T> - 只消费 T
// in T 允许 T 或 T 的父类
abstract class Consumer<in T> {
abstract fun consume(item: T)
}
class Animal
class Dog : Animal()
class AnimalConsumer : Consumer<Animal>() {
override fun consume(item: Animal) {
println("Consuming: $item")
}
}
fun main() {
// Consumer<Animal> 可以赋值给 Consumer<Dog>
val consumer: Consumer<Dog> = AnimalConsumer()
}
使用场景总结
| 关键字 | 用法 | 场景 |
|---|---|---|
out T | 返回 T | Producer, List |
in T | 消费 T | Consumer |
| 无标记 | 既返回又消费 | 容器 |
泛型实化 (reified)
reified 关键字
在 Kotlin 中,泛型参数在运行时会被擦除。但使用 reified 可以保留类型信息:
// 错误!类型会被擦除
fun <T> getType() = T::class.java
// 正确!inline + reified 保留类型信息
inline fun <reified T> getType(): KClass<T> = T::class
fun main() {
println(getType<String>()) // class java.lang.String
println(getType<Int>()) // class java.lang.Integer
println(getType<List<String>>()) // class java.util.Arrays$ArrayList
}
使用场景
inline fun <reified T> isInstance(value: Any): Boolean {
return value is T
}
inline fun <reified T> parse(json: String): T {
// 假设有 JSON 解析库
return parseJson(json, T::class.java)
}
fun main() {
println(isInstance<String>("Hello")) // true
println(isInstance<String>(123)) // false
val user = parse<User>(jsonString)
}
泛型与类型投影
类型投影
class Storage<T> {
var items: MutableList<T> = mutableListOf()
fun add(item: T) = items.add(item)
fun get(index: Int): T? = items.getOrNull(index)
}
// 投影 - 只读
fun copyTo(dest: Storage<in T>, src: Storage<out T>) {
for (i in 0 until (src.get(0)?.let { 10 } ?: 0)) {
src.get(i)?.let { dest.add(it) }
}
}
小结
本章我们学习了:
- 泛型基础:泛型类、泛型函数
- 类型约束:上界、多约束
- 可空泛型:类型参数的可空性
- 星号投影:
*的使用 - 协变与逆变:out/in 关键字
- 泛型实化:reified + inline
练习
- 创建一个泛型 Pair 类,包含 min 和 max 方法
- 编写泛型函数,实现 List 逆序
- 使用泛型约束,实现只接受数字类型的加法
- 理解并使用协变/逆变
- 使用 reified 获取泛型类型