「Kotlin 泛型深度图解:从入门到实战 + 委托框架揭秘」

「Kotlin 泛型深度图解:从入门到实战 + 委托框架揭秘」

一、泛型基础:为什么要用泛型

1.1 不用泛型的痛苦

kotlin 复制代码
// 没有泛型:只能用 Any,需要手动强转
val list = listOf(1, "hello", true)
val first = list[0] as Int  // 每次都要强转,麻烦且不安全

// 有泛型:类型自动推断,安全
val list = listOf(1, 2, 3)
val first: Int = list[0]  // 自动知道是 Int,不需要强转

1.2 泛型的本质

复制代码
┌─────────────────────────────────────┐
│        Generic Type                 │
│                                     │
│   List<T>  ←──── T 是类型参数       │
│   Map<K,V> ←──── K,V 是类型参数     │
│   Pair<A,B> ←─── A,B 是类型参数     │
└─────────────────────────────────────┘

调用时:
List<String>  → T = String
List<Int>     → T = Int
Map<String,Int> → K=String, V=Int

二、泛型类与函数

2.1 泛型类

kotlin 复制代码
// 泛型类
class Box<T>(val value: T) {
    fun get(): T = value
}

// 使用
val intBox = Box(123)           // 自动推断 T = Int
val stringBox = Box("hello")     // 自动推断 T = String
val explicitlyTyped = Box<Int>(456)

// 多类型参数
class PairBox<A, B>(val first: A, val second: B)

// 使用多类型参数
val pair = PairBox("name", 25)  // PairBox<String, Int>

2.2 泛型函数

kotlin 复制代码
// 泛型函数
fun <T> singletonList(item: T): List<T> = listOf(item)

// 多个类型参数
fun <K, V> makePair(key: K, value: V): Pair<K, V> = Pair(key, value)

// 使用
val list = singletonList(42)                    // List<Int>
val pair = makePair("age", 30)                  // Pair<String, Int>

2.3 类型约束

kotlin 复制代码
// T 必须继承或实现 Comparable
fun <T : Comparable<T>> max(a: T, b: T): T {
    return if (a >= b) a else b
}

// 使用
max(1, 2)           // OK,Int 实现了 Comparable
max("a", "b")        // OK,String 实现了 Comparable
// max(1, "a")       // ERROR,类型不一致

// 多个约束
fun <T> sortAndPrint(list: List<T>) where T : Comparable<T>, T : Any {
    list.sorted().forEach { println(it) }
}

三、泛型进阶:协变与逆变

3.1 核心问题

kotlin 复制代码
// 问题:List<String> 可以赋值给 List<Any> 吗?
val strings: List<String> = listOf("a", "b")
val anys: List<Any> = strings  // 编译错误!

// 为什么?因为可以这样:
anys.add(123)  // 把 Int 加入 String 列表!
strings[0]      // 取出时发现是 Int,类型安全崩塌

3.2 协变(out):只读安全

kotlin 复制代码
// 生产者用 out,只能读取,不能写入
class Producer<out T>(val item: T) {
    fun produce(): T = item
    // fun consume(item: T)  // ERROR,不能接收 T
}

// 效果:Producer<String> 是 Producer<Any> 的子类
val stringProducer: Producer<String> = Producer("hello")
val anyProducer: Producer<Any> = stringProducer  // OK!
val item: Any = anyProducer.produce()           // 读取的一定是 Any 或子类
复制代码
协变图解:
┌─────────────────────────────┐
│    Producer<out T>           │
│                             │
│   Producer<String> ──────▶ Producer<Any>    │
│   (子类型)        (父类型)   │
│                             │
│   箭头方向 = 类型参数方向    │
│   out = 只生产,不消费      │
└─────────────────────────────┘

3.3 逆变(in):只写安全

kotlin 复制代码
// 消费者用 in,只能写入,不能读取
class Consumer<in T> {
    fun consume(item: T) {
        println("Consuming: $item")
    }
    // fun produce(): T  // ERROR,不能返回 T
}

// 效果:Consumer<Any> 是 Consumer<String> 的子类
val anyConsumer: Consumer<Any> = Consumer()
val stringConsumer: Consumer<String> = anyConsumer  // OK!
stringConsumer.consume("hello")                     // 写入的一定是 String 或子类
anyConsumer.consume(123)                            // 但实际存的是 Any,也 OK
复制代码
逆变图解:
┌─────────────────────────────┐
│    Consumer<in T>           │
│                             │
│   Consumer<Any> ──────▶ Consumer<String>   │
│   (子类型)        (父类型)   │
│                             │
│   in = 只消费,不生产        │
└─────────────────────────────┘

3.4 生活中的类比

场景 协变 (out) 逆变 (in)
食品工厂 生产线产出食品 不能往生产线消费原料
垃圾桶 只能往里扔垃圾 只能从里面取垃圾
Kotlin Producer<out T> Consumer<in T>
对称性 生产者只能产出 消费者只能接收

3.5 实际应用

kotlin 复制代码
// JDK 的 Comparable 就是协变
// public interface Comparable<out T>

// Kotlin 的 List 也是协变(只读)
// public interface List<out E>

// Function 的逆变
// public interface Function1<in P1, out R>
// P1 是逆变参数(输入),R 是协变参数(输出)

四、泛型约束与类型擦除

4.1 类型擦除

kotlin 复制代码
// JVM 的泛型是通过类型擦除实现的
class MyBox<T> {
    fun get(): T? = null
}

// 编译后变成
class MyBox {
    fun get(): Object? = null  // T 被擦除为 Object
}

// 所以运行时无法直接判断泛型类型
val list: List<String> = listOf("a")
// list is List<Int>  // ERROR,运行时不知道 T 是什么

4.2 实化类型(Reified)

kotlin 复制代码
// 普通泛型函数不能检查类型
fun <T> checkType(item: Any) = item is T  // ERROR

// 内联函数可以使用 reified
inline fun <reified T> checkType(item: Any) = item is T

// 现在可以了
checkType<String>("hello")  // true
checkType<String>(123)       // false

4.3 星号投影(*)

kotlin 复制代码
// 不关心具体类型,用 *
val list: List<*> = listOf("a", "b", "c")
val any: Any = list[0]  // 安全的未知类型

// 用于不知道类型参数的情况
fun printFirst(list: List<*>) {
    println(list.firstOrNull())
}

五、自定义 lazy 延迟加载函数

5.1 标准 lazy 原理

kotlin 复制代码
// 标准库的 lazy
val lazyValue: String by lazy {
    println("Computing...")
    "Hello"
}

// 使用时
println(lazyValue)  // 打印 "Computing...",然后返回 "Hello"
println(lazyValue)  // 直接返回 "Hello",不会再执行

5.2 自己实现 lazy

kotlin 复制代码
/**
 * 自定义 Lazy 延迟加载委托
 *
 * @param initializer 初始化函数,返回 T 类型的值
 */
fun <T> myLazy(initializer: () -> T): Lazy<T> = MyLazyImpl(initializer)

/**
 * Lazy 接口的自定义实现
 */
class MyLazyImpl<T>(private val initializer: () -> T) : Lazy<T> {
    private var _cachedValue: Any? = UNINITIALIZED
    private var _isInitialized = false

    override val value: T
        get() {
            if (_isInitialized) {
                @Suppress("UNCHECKED_CAST")
                return _cachedValue as T
            }

            val result = initializer()
            _cachedValue = result
            _isInitialized = true
            return result
        }

    override fun isInitialized(): Boolean = _isInitialized

    companion object {
        private object UNINITIALIZED
    }
}

// 使用方式完全相同
val value: String by myLazy {
    println("只执行一次!")
    "延迟加载的结果"
}

5.3 线程安全版本

kotlin 复制代码
import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.locks.ReentrantLock

/**
 * 线程安全的 Lazy 委托实现
 */
class ThreadSafeLazy<T>(private val initializer: () -> T) : Lazy<T> {
    @Volatile
    private var _value: Any? = UNINITIALIZED
    @Volatile
    private var _lock = ReentrantLock()

    override val value: T
        get() {
            if (_value !== UNINITIALIZED) {
                @Suppress("UNCHECKED_CAST")
                return _value as T
            }

            _lock.lock()
            try {
                if (_value !== UNINITIALIZED) {
                    @Suppress("UNCHECKED_CAST")
                    return _value as T
                }

                val result = initializer()
                _value = result
                return result
            } finally {
                _lock.unlock()
            }
        }

    override fun isInitialized(): Boolean = _value !== UNINITIALIZED

    companion object {
        private object UNINITIALIZED
    }
}

/**
 * 创建线程安全的延迟加载属性
 */
fun <T> threadSafeLazy(initializer: () -> T): Lazy<T> = ThreadSafeLazy(initializer)

5.4 使用 CAS 无锁版本(更高效)

kotlin 复制代码
import java.util.concurrent.atomic.AtomicReference

/**
 * 使用 CAS 实现的无锁 Lazy(高性能版本)
 */
class LockFreeLazy<T>(private val initializer: () -> T) : Lazy<T> {
    private val storage = AtomicReference<Any?>(UNINITIALIZED)

    override val value: T
        get() {
            // 快速路径:已初始化
            val stored = storage.get()
            if (stored !== UNINITIALIZED) {
                @Suppress("UNCHECKED_CAST")
                return stored as T
            }

            // 慢速路径:需要初始化
            return initialize()
        }

    private fun initialize(): T {
        // 尝试用 initializer 初始化
        val result = initializer()

        // CAS:如果当前是 UNINITIALIZED,则设置为结果
        if (storage.compareAndSet(UNINITIALIZED, result)) {
            @Suppress("UNCHECKED_CAST")
            return result as T
        }

        // 如果 CAS 失败,说明已经被其他线程初始化了
        @Suppress("UNCHECKED_CAST")
        return storage.get() as T
    }

    override fun isInitialized(): Boolean = storage.get() !== UNINITIALIZED

    companion object {
        private object UNINITIALIZED
    }
}

5.5 最终的使用示例

kotlin 复制代码
data class User(val name: String, val age: Int)

// 1. 基础版本(单线程)
val user1: User by myLazy {
    println("初始化 User 1")
    User("张三", 25)
}

// 2. 线程安全版本(多线程推荐)
val user2: User by threadSafeLazy {
    println("初始化 User 2")
    User("李四", 30)
}

// 3. 无锁版本(高性能)
val user3: User by LockFreeLazy {
    println("初始化 User 3")
    User("王五", 35)
}

// 测试
fun main() {
    println("--- 开始 ---")
    println(user1.name)  // 第一次访问才会初始化
    println(user1.name)  // 第二次直接返回缓存值
    println("--- 结束 ---")
}

六、委托(Delegation)机制

6.1 类委托

kotlin 复制代码
// 接口
interface Base {
    fun print()
}

// 实现类
class BaseImpl(val x: Int) : Base {
    override fun print() = println(x)
}

// 委托类
class Derived(b: Base) : Base by b

// 使用
val b = BaseImpl(10)
val d = Derived(b)
d.print()  // 调用委托对象的 print(),输出 10

6.2 属性委托

kotlin 复制代码
// 定义可委托的属性接口
interface ReadOnlyProperty<in R, out T> {
    operator fun getValue(thisRef: R, property: KProperty<*>): T
}

interface ReadWriteProperty<in R, T> {
    operator fun getValue(thisRef: R, property: KProperty<*>): T
    operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}

// 自定义委托
class MyDelegate(var value: String = "default") {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("读取: ${property.name}")
        return value
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: String) {
        println("写入: ${property.name} = $newValue")
        value = newValue
    }
}

// 使用
class Example {
    var myProp: String by MyDelegate()
}

val e = Example()
e.myProp = "hello"    // 输出: 写入: myProp = hello
println(e.myProp)     // 输出: 读取: myProp, hello

6.3 常用标准库委托

kotlin 复制代码
// 1. lazy - 延迟初始化
val heavyObject: ExpensiveClass by lazy { ExpensiveClass() }

// 2. observable - 属性变化监听
class User {
    var name: String by Delegates.observable("default") { property, old, new ->
        println("${property.name}: $old → $new")
    }
}

// 3. vetoable - 可否决的变化
var score: Int by Delegates.vetoable(0) { property, old, new ->
    new > old  // 只允许增加
}

// 4. notNull - 可空但不初始化的属性
var lazyInitString: String by Delegates.notNull<String>()

七、泛型与委托的综合应用

7.1 委托工厂

kotlin 复制代码
// 通用委托工厂
class DelegateFactory<T>(private val creator: () -> T) : Lazy<T> {
    private var instance: T? = null

    override val value: T
        get() {
            if (instance == null) {
                instance = creator()
            }
            return instance!!
        }

    override fun isInitialized(): Boolean = instance != null
}

fun <T> delegate(creator: () -> T): Lazy<T> = DelegateFactory(creator)

// 使用
class DatabaseConnection {
    companion object {
        val instance: DatabaseConnection by delegate {
            println("建立数据库连接...")
            DatabaseConnection()
        }
    }
}

7.2 泛型委托的实战:属性校验

kotlin 复制代码
class ValidatedProperty<T>(
    initialValue: T,
    private val validator: (T) -> Boolean
) {
    private var _value: T = initialValue

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T = _value

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        require(validator(value)) { "Validation failed for ${property.name}: $value" }
        _value = value
    }
}

class User {
    var name: String by ValidatedProperty("") { it.isNotBlank() }
    var age: Int by ValidatedProperty(0) { it in 0..150 }
    var email: String by ValidatedProperty("") { it.contains("@") }
}

// 使用
val user = User()
user.name = "张三"
// user.name = ""  // ERROR: Validation failed for name:
// user.age = -1   // ERROR: Validation failed for age:
// user.email = "test"  // ERROR: Validation failed for email:

7.3 泛型 + 委托 + 协变:事件总线

kotlin 复制代码
/**
 * 类型安全的事件总线
 * 使用协变 out T 让订阅者可以接收子类事件
 */
class EventBus {
    private val handlers = mutableMapOf<String, MutableList<(Any) -> Unit>>()

    // 注册处理器,协变允许传入子类
    @Suppress("UNCHECKED_CAST")
    fun <T : Any> subscribe(eventType: KClass<T>, handler: (T) -> Unit) {
        val key = eventType.qualifiedName ?: return
        handlers.getOrPut(key) { mutableListOf() }.add(handler as (Any) -> Unit)
    }

    // 发布事件
    @Suppress("UNCHECKED_CAST")
    fun <T : Any> publish(event: T) {
        val key = event::class.qualifiedName ?: return
        handlers[key]?.forEach { it(event as Any) }
    }
}

// 使用
sealed class Event
class ClickEvent(val x: Int, val y: Int) : Event()
class KeyEvent(val key: String) : Event()

val bus = EventBus()
bus.subscribe(ClickEvent::class) { event ->
    println("点击坐标: ${event.x}, ${event.y}")
}
bus.subscribe(KeyEvent::class) { event ->
    println("按键: ${event.key}")
}

bus.publish(ClickEvent(100, 200))
bus.publish(KeyEvent("Enter"))

八、知识总结

复制代码
┌──────────────────────────────────────────────────────────────┐
│                    Kotlin 泛型体系                             │
├──────────────────────────────────────────────────────────────┤
│  泛型基础                    │  泛型进阶                       │
│  ├── 泛型类 <T>              │  ├── 协变 <out T>              │
│  ├── 泛型函数 <T>            │  │    只读,生产者            │
│  └── 类型约束 <T : X>        │  ├── 逆变 <in T>             │
│                              │  │    只写,消费者            │
│  类型擦除                    │  └── reified + inline        │
│  ├── 运行时类型被擦除          │                                │
│  └── 可用 inline + reified   │  委托                          │
│                              │  ├── 类委托 by                 │
│                              │  ├── 属性委托 by               │
│                              │  │    getValue/setValue       │
│                              │  └── 标准库: lazy, observable  │
└──────────────────────────────────────────────────────────────┘

核心要点速记

概念 关键字 场景
生产者泛型 out T 函数返回 T,只读
消费者泛型 in T 函数参数 T,只写
类型约束 <T : Comparable> T 必须实现某接口
实化类型 reified T inline 函数才能用
延迟加载 by lazy {} 耗时操作懒执行
属性监听 by observable {} 属性变化通知

九、自定义 lazy 函数完整代码

kotlin 复制代码
package com.example.utils

import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.locks.ReentrantLock

/**
 * 自定义 Lazy 延迟加载委托 - 单线程版本
 */
fun <T> myLazy(initializer: () -> T): Lazy<T> = MyLazyImpl(initializer)

class MyLazyImpl<T>(private val initializer: () -> T) : Lazy<T> {
    private var _cachedValue: Any? = UNINITIALIZED
    private var _isInitialized = false

    override val value: T
        get() {
            if (_isInitialized) {
                @Suppress("UNCHECKED_CAST")
                return _cachedValue as T
            }
            val result = initializer()
            _cachedValue = result
            _isInitialized = true
            return result
        }

    override fun isInitialized(): Boolean = _isInitialized

    companion object {
        private object UNINITIALIZED
    }
}

/**
 * 线程安全版本 - 使用 ReentrantLock
 */
class ThreadSafeLazy<T>(private val initializer: () -> T) : Lazy<T> {
    @Volatile
    private var _value: Any? = UNINITIALIZED
    private val _lock = ReentrantLock()

    override val value: T
        get() {
            if (_value !== UNINITIALIZED) {
                @Suppress("UNCHECKED_CAST")
                return _value as T
            }
            _lock.lock()
            try {
                if (_value !== UNINITIALIZED) {
                    @Suppress("UNCHECKED_CAST")
                    return _value as T
                }
                val result = initializer()
                _value = result
                return result
            } finally {
                _lock.unlock()
            }
        }

    override fun isInitialized(): Boolean = _value !== UNINITIALIZED

    companion object {
        private object UNINITIALIZED
    }
}

/**
 * 高性能无锁版本 - 使用 CAS
 */
class LockFreeLazy<T>(private val initializer: () -> T) : Lazy<T> {
    private val storage = AtomicReference<Any?>(UNINITIALIZED)

    override val value: T
        get() {
            val stored = storage.get()
            if (stored !== UNINITIALIZED) {
                @Suppress("UNCHECKED_CAST")
                return stored as T
            }
            val result = initializer()
            if (storage.compareAndSet(UNINITIALIZED, result)) {
                @Suppress("UNCHECKED_CAST")
                return result as T
            }
            @Suppress("UNCHECKED_CAST")
            return storage.get() as T
        }

    override fun isInitialized(): Boolean = storage.get() !== UNINITIALIZED

    companion object {
        private object UNINITIALIZED
    }
}

// 使用方式
class Example {
    // 单线程环境用这个
    val heavyData: List<String> by myLazy {
        println("加载数据...")
        listOf("a", "b", "c")
    }

    // 多线程环境推荐这个
    val threadSafeData: Map<String, Int> by ThreadSafeLazy {
        println("加载配置...")
        mapOf("timeout" to 5000)
    }

    // 高并发场景用这个
    val cacheData: String by LockFreeLazy {
        println("加载缓存...")
        "cached_value"
    }
}
相关推荐
私人珍藏库2 小时前
[Windows] 360ChromeX(360极速浏览器X)_vv23.1.1216.64 便携版
windows·工具·软件·win·多功能
人道领域2 小时前
【LeetCode刷题日记】225.用队列实现栈--三招实现栈操作(多种思维)
java·开发语言·算法·leetcode·面试
Mr_pyx2 小时前
【告别for循环】Java Stream 流式编程精通:从入门到源码级的性能优化
java·开发语言·性能优化
:1212 小时前
java基础--数组
java·开发语言
KillerNoBlood2 小时前
KMP性能优势与实战要点
kotlin
爱上好庆祝2 小时前
学习js第一天(出发新世界)
开发语言·前端·javascript·css·学习·html·ecmascript
小短腿的代码世界2 小时前
Qwt性能优化与源码级深度解析:工业级图表控件的极限性能调优
开发语言·qt·信息可视化·性能优化
深念Y2 小时前
Docker Windows C盘爆满迁移到D盘:完整试错与成功路径
windows·docker·wsl·镜像·清理·迁移·c盘
lsx2024062 小时前
jQuery UI 实例
开发语言