跳到主要内容

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
}

为什么使用泛型?

  1. 类型安全:编译时检查类型错误
  2. 代码复用:一套代码处理多种类型
  3. 性能提升:无需装箱/拆箱
// 不使用泛型 - 类型不安全
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返回 TProducer, List
in T消费 TConsumer
无标记既返回又消费容器

泛型实化 (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) }
}
}

小结

本章我们学习了:

  1. 泛型基础:泛型类、泛型函数
  2. 类型约束:上界、多约束
  3. 可空泛型:类型参数的可空性
  4. 星号投影* 的使用
  5. 协变与逆变:out/in 关键字
  6. 泛型实化:reified + inline

练习

  1. 创建一个泛型 Pair 类,包含 min 和 max 方法
  2. 编写泛型函数,实现 List 逆序
  3. 使用泛型约束,实现只接受数字类型的加法
  4. 理解并使用协变/逆变
  5. 使用 reified 获取泛型类型