Kotlin 泛型

Kotlin 泛型(2025年中文讲解)

泛型(Generics)是 Kotlin 提供的一种强大特性,允许在定义类、接口、函数时使用类型参数,从而提高代码的灵活性和类型安全性。相比 Java,Kotlin 的泛型语法更简洁,支持协变(out)逆变(in)类型擦除优化,结合空安全和函数式编程,广泛应用于 Android(Jetpack Compose)、后端(Spring Boot)和 Kotlin Multiplatform(KMP)项目。2025年,Kotlin 2.0(K2 编译器)优化了泛型性能和类型推断,尤其在 KMP 跨平台开发中泛型是共享逻辑的核心。本教程详细讲解 Kotlin 泛型的语法、用法和实践,基于官方文档、CSDN 和知乎,适合初学者和开发者。建议用 Kotlin Playground(https://play.kotlinlang.org/)练习。


一、Kotlin 泛型概览(必知)

  • 核心概念
  • 泛型:通过类型参数(TK 等)定义类、接口或函数,延迟类型绑定。
  • 类型安全:编译时检查类型,减少运行时错误。
  • 协变/逆变:通过 outin 关键字控制类型关系。
  • 特点
  • 简洁:类型推断减少显式类型声明。
  • 空安全:支持可空泛型类型(如 T?)。
  • 灵活:支持泛型类、接口、函数和扩展。
  • 2025年趋势
  • Kotlin 2.0 优化泛型类型推断(性能提升约 20%)。
  • Android 开发中,泛型用于 ViewModel 和 Compose 数据流。
  • KMP 项目中,泛型结合 expect/actual 实现跨平台类型安全。

二、核心语法与用法(必会)

以下按泛型类、函数、协变/逆变等模块讲解,包含代码示例,直接可运行。

1. 泛型类
  • 语法:用 <T> 定义类型参数,T 可代表任意类型。
  class Box<T>(val item: T) {
      fun getItem(): T = item
  }
  fun main() {
      val intBox = Box<Int>(42)
      val stringBox = Box<String>("Kotlin")
      println(intBox.getItem()) // 输出:42
      println(stringBox.getItem()) // 输出:Kotlin
  }
  • 说明
  • T 是类型参数,创建实例时指定具体类型(如 IntString)。
  • 支持类型推断: val box = Box("Hello") // 自动推断为 Box<String>
  • 空安全
  class NullableBox<T>(val item: T?) {
      fun isEmpty(): Boolean = item == null
  }
  fun main() {
      val box = NullableBox<String?>(null)
      println(box.isEmpty()) // 输出:true
  }
2. 泛型函数
  • 语法:在函数名前用 <T> 定义类型参数。
  fun <T> printItem(item: T) {
      println("Item: $item")
  }
  fun main() {
      printItem(42) // 输出:Item: 42
      printItem("Kotlin") // 输出:Item: Kotlin
  }
  • 类型约束:限制 T 的类型范围,用 where:
  fun <T : Number> sum(a: T, b: T): Double {
      return a.toDouble() + b.toDouble()
  }
  fun main() {
      println(sum(5, 3)) // 输出:8.0
      // println(sum("A", "B")) // 错误:String 非 Number
  }
  • 多约束
    kotlin fun <T> printIfComparable(item: T) where T : Comparable<T>, T : CharSequence { println(item.compareTo(item)) } fun main() { printIfComparable("Kotlin") // 输出:0 }
3. 泛型接口
  • 语法:接口支持泛型,类实现时指定类型。
  interface Repository<T> {
      fun get(id: Int): T
      fun add(item: T)
  }
  class StringRepository : Repository<String> {
      private val items = mutableListOf<String>()
      override fun get(id: Int): String = items[id]
      override fun add(item: String) = items.add(item)
  }
  fun main() {
      val repo = StringRepository()
      repo.add("Kotlin")
      println(repo.get(0)) // 输出:Kotlin
  }
4. 协变(out)
  • 用途:允许父类型引用子类型(如 List<Any> 接受 List<String>)。
  • 语法:在类型参数前加 out,表示只读(生产者)。
  interface Producer<out T> {
      fun produce(): T
  }
  class StringProducer : Producer<String> {
      override fun produce() = "Kotlin"
  }
  fun main() {
      val producer: Producer<Any> = StringProducer()
      println(producer.produce()) // 输出:Kotlin
  }
  • 说明out T 限制 T 只用于输出(如返回值),不可用于输入(如参数)。
5. 逆变(in)
  • 用途:允许子类型引用父类型(如 Consumer<Any> 接受 Consumer<String>)。
  • 语法:用 in,表示只写(消费者)。
  interface Consumer<in T> {
      fun consume(item: T)
  }
  class AnyConsumer : Consumer<Any> {
      override fun consume(item: Any) = println("Consumed: $item")
  }
  fun main() {
      val consumer: Consumer<String> = AnyConsumer()
      consumer.consume("Kotlin") // 输出:Consumed: Kotlin
  }
6. 泛型扩展
  • 语法:为泛型类型添加扩展函数。
  fun <T> List<T>.secondOrNull(): T? = if (size >= 2) this[1] else null
  fun main() {
      val numbers = listOf(1, 2, 3)
      println(numbers.secondOrNull()) // 输出:2
      val empty = emptyList<String>()
      println(empty.secondOrNull()) // 输出:null
  }
7. 类型擦除
  • 说明:Kotlin(基于 JVM)运行时擦除泛型信息,需用 reified 解决。
  inline fun <reified T> isInstanceOf(obj: Any): Boolean {
      return obj is T
  }
  fun main() {
      println(isInstanceOf<String>("Kotlin")) // 输出:true
      println(isInstanceOf<Int>("Kotlin")) // 输出:false
  }
  • 注意reified 需配合 inline 函数,用于运行时类型检查。

三、实践示例(综合应用)

  1. 命令行示例(泛型容器)
class Container<T>(private val item: T) {
    fun getItem(): T = item
    fun <R> transform(transformer: (T) -> R): Container<R> {
        return Container(transformer(item))
    }
}

fun main() {
    val intContainer = Container(42)
    println(intContainer.getItem()) // 输出:42
    val stringContainer = intContainer.transform { it.toString() }
    println(stringContainer.getItem()) // 输出:42(字符串)
}
  1. Android 示例(泛型 ViewModel)
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider

class GenericViewModel<T>(private val data: T) : ViewModel() {
    fun getData(): T = data
}

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val button: Button = findViewById(R.id.button)
        val textView: TextView = findViewById(R.id.textView)
        val viewModel = ViewModelProvider(this)[GenericViewModel::class.java] as GenericViewModel<String>
        button.setOnClickListener {
            textView.text = viewModel.getData()
        }
    }
}


布局(res/layout/activity_main.xml

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Press button" />
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show Data" />
</LinearLayout>


功能:点击按钮显示 ViewModel 中的泛型数据(需初始化 ViewModel 数据)。


四、注意事项与最佳实践

  1. 类型约束
  • where: 限制类型,避免无效调用:
    kotlin fun <T : Number> toDouble(value: T): Double = value.toDouble()
  1. 协变与逆变
  • out 表示生产者(如只读 List),in 表示消费者(如写入函数)。
  • 避免复杂协变/逆变嵌套,影响可读性。
  1. 类型擦除
  • 使用 reifiedinline 解决运行时类型问题。
  • 避免在非内联函数中直接访问 T 的类型。
  1. 空安全
  • 泛型类型支持 T?
    kotlin class Box<T>(val item: T?) { fun isEmpty() = item == null }
  1. 2025年趋势
  • Jetpack Compose:泛型用于 State 和 ViewModel 数据流。
  • KMP:泛型结合 expect/actual 实现跨平台:
    kotlin expect interface Repository<T> { fun get(id: Int): T }
  • AI 辅助:IntelliJ 的 Codeium 插件可生成泛型类和函数。

五、学习建议

  • 练习:用 Kotlin Playground 实践泛型类、函数和协变/逆变,写容器或转换器。
  • 资源
  • 官方文档:https://kotlinlang.org/docs/generics.html
  • B站:尚硅谷 Kotlin 教程(免费,包含泛型)。
  • CSDN:搜索“Kotlin 泛型”。
  • 时间:2-3 天掌握泛型基础,1 周熟悉 Android/KMP 应用。
  • 实践:开发小型 App(如泛型数据列表、跨平台 Repository)。

六、总结

Kotlin 泛型必知类型参数、协变(out)、逆变(in)和类型擦除,必会定义泛型类、函数和扩展,处理空安全。2025年,Kotlin 2.0 提升泛型性能,Android(Compose)和 KMP 项目中泛型确保类型安全和代码复用。相比 Java,Kotlin 泛型更简洁、灵活,适合快速开发。

如果需要具体场景代码(如 Compose 泛型 State 或 KMP 示例)或有问题,告诉我,我可以提供更详细解答!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注