一文弄懂Kotlin中的by关键字

35 阅读2分钟

在 Kotlin 中,by 关键字用于实现委托模式(Delegation)​,它允许将某些操作或责任委托给另一个对象来处理。by 主要有两种用途:​类委托属性委托


1. 类委托(Class Delegation)

通过 by 关键字,可以将类的接口实现委托给另一个对象。这样可以在不继承的情况下复用现有类的功能。

示例:

interface Animal {
    fun makeSound()
}

class Dog : Animal {
    override fun makeSound() {
        println("Woof!")
    }
}

// 通过 by 将 Animal 接口的实现委托给 dog 对象
class Robot(private val dog: Dog) : Animal by dog {
    fun move() {
        println("Robot is moving")
    }
}

fun main() {
    val dog = Dog()
    val robot = Robot(dog)
    robot.makeSound() // 实际调用的是 Dog 的 makeSound()
    robot.move()      // Robot 的独有方法
}
  • 作用​:Robot 类通过 by dog 委托了 Animal 接口的实现,无需手动重写 makeSound()
  • 优势​:避免重复代码,优先组合而非继承。

2. 属性委托(Property Delegation)

通过 by 将属性的 getter/setter 逻辑委托给一个委托对象​(需实现 getValue() 和 setValue() 方法)。Kotlin 标准库提供了几种常用委托:

常见用途:

(1)懒加载委托 lazy

属性在首次访问时初始化。

val heavyData: String by lazy {
    println("Computing heavy data...")
    "Heavy Result"
}

fun main() {
    println(heavyData) // 第一次访问时计算并缓存
    println(heavyData) // 直接返回缓存结果
}
(2)观察者委托 Delegates.observable

属性变化时触发回调。

import kotlin.properties.Delegates

var name: String by Delegates.observable("Alice") { _, old, new ->
    println("Name changed: $old -> $new")
}

fun main() {
    name = "Bob" // 输出: Name changed: Alice -> Bob
}
(3)非空校验委托 Delegates.notNull

延迟初始化但确保非空。

var age: Int by Delegates.notNull<Int>()

fun main() {
    age = 30
    println(age) // 必须先赋值,否则抛 IllegalStateException
}
(4)自定义委托

实现 ReadWriteProperty 或 ReadOnlyProperty 接口。

class StringDelegate(private var value: String) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("Getting value: $value")
        return value
    }

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

var text by StringDelegate("Default")

fun main() {
    println(text) // 输出: Getting value: Default
    text = "New"  // 输出: Setting value: New
}

关键点总结:

  • 类委托​:通过 by 将接口实现委托给其他对象。
  • 属性委托​:将属性的访问逻辑委托给 lazyobservable 或自定义对象。
  • 优势​:减少重复代码,实现关注点分离(如懒加载、观察模式等)。

通过 by,Kotlin 以简洁的语法实现了强大的委托模式,是 Kotlin 特色功能之一。