Skip to content

Kotlin 委托属性详解 🔧

Android 面试必考 Kotlin 委托属性,包含 by 关键字、标准委托、自定义委托、委托属性原理等核心知识点


目录

  1. by 关键字
  2. [标准委托(lazy、observable、vetoable、map)](#2-标准委托 lazyobservablevetoablemap)
  3. 自定义委托
  4. 委托属性原理
  5. ReadWriteProperty/ReadOnlyProperty
  6. 面试考点汇总

1. by 关键字

1.1 基础语法

委托属性允许将属性的 getter/setter 委托给另一个对象处理:

kotlin
// 基本语法:val/var 属性名:类型 by 委托对象
class Example {
    var property: String by Delegate()
}

// 委托类需要实现 getValue 和 setValue
class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "value"
    }
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        // 处理赋值
    }
}

1.2 委托属性的使用

kotlin
// 委托类
class Delegate {
    private var value: String = ""
    
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("Getting ${property.name}")
        return value
    }
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("Setting ${property.name} to $value")
        this.value = value
    }
}

// 使用委托属性
class Example {
    var property: String by Delegate()
}

// 使用
val example = Example()
example.property = "Hello"  // 调用 setValue
println(example.property)   // 调用 getValue

1.3 委托的要求

kotlin
// 对于 var 属性,委托需要 getValue 和 setValue
class VarDelegate<T> {
    private var value: T? = null
    
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value as T
    }
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}

// 对于 val 属性,只需要 getValue
class ValDelegate<T>(private val initialValue: T) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return initialValue
    }
}

// 使用
class Example {
    var varProp: String by VarDelegate()
    val valProp: String by ValDelegate("initial")
}

1.4 委托属性的实际场景

kotlin
// 1. 懒加载
class Config {
    val data: String by lazy {
        println("Loading config...")
        loadConfigFromFile()
    }
}

// 2. 可观察属性
class User {
    var name: String by Delegates.observable("<no name>") {
        property, old, new ->
        println("$property changed from $old to $new")
    }
}

// 3. 非空属性
class Presenter {
    lateinit var view: View
    // 或
    var view: View? by NotNullVar()
}

// 4. Map 委托
class User(map: Map<String, Any?>) {
    val name: String by map
    val age: Int by map
}

2. 标准委托(lazy、observable、vetoable、map)

2.1 lazy 委托

kotlin
// 基础用法
class Example {
    val value: String by lazy {
        println("Computing...")
        "Hello"
    }
}

// 使用
val example = Example()
println(example.value)  // 第一次:打印 "Computing..." 然后 "Hello"
println(example.value)  // 第二次:只打印 "Hello"

// lazy 的三种模式
val lazy1 by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { compute() }
// 默认,线程安全,使用锁保证只计算一次

val lazy2 by lazy(LazyThreadSafetyMode.PUBLICATION) { compute() }
// 多线程初始化,可能多次计算,但返回相同结果

val lazy3 by lazy(LazyThreadSafetyMode.NONE) { compute() }
// 单线程,最快,无锁

// 实际场景
class Repository {
    private val database: Database by lazy {
        Database.connect()
    }
    
    private val api: ApiService by lazy {
        Retrofit.Builder().build()
    }
}

2.2 lazy 的实现原理

kotlin
// lazy 返回 Lazy<T> 接口
public interface Lazy<out T> {
    public val value: T
    public fun isInitialized(): Boolean
}

// 实现类(简化版)
private class SynchronizedLazyImpl<out T>(
    private val initializer: () -> T,
    private val lock: Any = this
) : Lazy<T>, Serializable {
    @Volatile private var value: Any? = UNINITIALIZED_VALUE
    
    override val value: T
        get() {
            val v = value
            if (v !== UNINITIALIZED_VALUE) {
                @Suppress("UNCHECKED_CAST")
                return v as T
            }
            
            return synchronized(lock) {
                val v2 = value
                if (v2 !== UNINITIALIZED_VALUE) {
                    @Suppress("UNCHECKED_CAST")
                    v2 as T
                } else {
                    val typedValue = initializer()
                    value = typedValue
                    typedValue
                }
            }
        }
    
    override fun isInitialized(): Boolean = value !== UNINITIALIZED_VALUE
}

// 使用
val lazyValue: String by lazy { "Hello" }
println(lazyValue)  // 初始化
println((lazyValue as Lazy<*>).isInitialized())  // true

2.3 observable 委托

kotlin
// 基础用法
import kotlin.properties.Delegates

class User {
    var name: String by Delegates.observable("<no name>") {
        property, old, new ->
        println("$property changed from $old to $new")
    }
}

// 使用
val user = User()
user.name = "张三"  // 打印:property name changed from <no name> to 张三
user.name = "李四"  // 打印:property name changed from 张三 to 李四

// 实际场景:通知 UI 更新
class ViewModel {
    var userName: String by Delegates.observable("") { _, _, _ ->
        notifyUiChanged()
    }
    
    private fun notifyUiChanged() {
        // 通知 UI 更新
    }
}

// 多个观察者
class ObservableExample {
    private val observers = mutableListOf<(String) -> Unit>()
    
    fun addObserver(observer: (String) -> Unit) {
        observers.add(observer)
    }
    
    var value: String by Delegates.observable("") { _, old, new ->
        observers.forEach { it(new) }
    }
}

2.4 vetoable 委托

kotlin
// 基础用法:可以拒绝更新
import kotlin.properties.Delegates

class User {
    var age: Int by Delegates.vetoable(0) { property, old, new ->
        if (new < 0) {
            println("Age cannot be negative")
            false  // 拒绝更新
        } else if (new > 150) {
            println("Age cannot be greater than 150")
            false  // 拒绝更新
        } else {
            true  // 允许更新
        }
    }
}

// 使用
val user = User()
user.age = 25  // ✅ 允许
user.age = -1  // ❌ 拒绝,保持原值
user.age = 200 // ❌ 拒绝,保持原值

// 实际场景:状态机
class StateMachine {
    var state: State by Delegates.vetoable(State.Initial) { _, old, new ->
        when {
            old == State.Initial && new == State.Loading -> true
            old == State.Loading && new == State.Success -> true
            old == State.Loading && new == State.Error -> true
            else -> {
                println("Invalid state transition: $old -> $new")
                false
            }
        }
    }
}

enum class State { Initial, Loading, Success, Error }

2.5 map 委托

kotlin
// 基础用法:从 Map 中读取/写入值
class User(map: Map<String, Any?>) {
    val name: String by map
    val age: Int by map
}

// 使用
val user = User(mapOf(
    "name" to "张三",
    "age" to 25
))
println(user.name)  // "张三"
println(user.age)   // 25

// 可变 Map 委托
class MutableUser(map: MutableMap<String, Any?>) {
    var name: String by map
    var age: Int by map
}

// 使用
val mutableMap = mutableMapOf<String, Any?>()
val mutableUser = MutableUser(mutableMap)
mutableUser.name = "李四"
mutableUser.age = 30
println(mutableMap)  // {name=李四,age=30}

// 实际场景:JSON 解析
class JsonUser(json: Map<String, Any?>) {
    val id: Int by json
    val name: String by json
    val email: String? by json  // 可空
}

// 带默认值
class UserWithDefault(map: Map<String, Any?>) {
    val name: String by map.withDefault { "Unknown" }
    val age: Int by map.withDefault { 0 }
}

2.6 其他标准委托

kotlin
// notNull 委托(已废弃,使用 lateinit 或可空类型)
class NotNullExample {
    var name: String by Delegates.notNull()
    
    fun init() {
        name = "Kotlin"
    }
}

// 使用
val example = NotNullExample()
// println(example.name)  // ❌ 抛 IllegalStateException
example.init()
println(example.name)  // ✅ "Kotlin"

// 推荐替代方案
class BetterExample {
    lateinit var name: String
    // 或
    var name: String? = null
}

3. 自定义委托

3.1 基础自定义委托

kotlin
// 实现 ReadWriteProperty 接口
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

class NotNullVar<T> : ReadWriteProperty<Any?, T> {
    private var value: T? = null
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value ?: throw IllegalStateException(
            "Property ${property.name} not initialized"
        )
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}

// 使用
class Example {
    var name: String by NotNullVar()
}

// 实际使用
val example = Example()
// println(example.name)  // ❌ 抛异常
example.name = "Kotlin"
println(example.name)  // ✅ "Kotlin"

3.2 延迟初始化委托

kotlin
// 自定义延迟初始化
class LateInit<T> : ReadWriteProperty<Any?, T> {
    private var value: T? = null
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value ?: throw IllegalStateException(
            "Property ${property.name} has not been initialized"
        )
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        if (this.value != null) {
            throw IllegalStateException("Property ${property.name} already initialized")
        }
        this.value = value
    }
    
    val isInitialized: Boolean
        get() = value != null
}

// 使用
class Example {
    var config: Config by LateInit()
}

// 实际场景:依赖注入
class DIContainer {
    private val services = mutableMapOf<String, Any>()
    
    fun <T : Any> register(name: String, service: T) {
        services[name] = service
    }
    
    @Suppress("UNCHECKED_CAST")
    fun <T : Any> get(name: String): T {
        return services[name] as? T
            ?: throw IllegalStateException("Service $name not registered")
    }
}

class ServiceDelegate<T : Any>(private val name: String) : ReadWriteProperty<Any?, T> {
    private val container = DIContainer()
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return container.get(name)
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        container.register(name, value)
    }
}

// 使用
class MyService
class AnotherService

class Client {
    var service: MyService by ServiceDelegate("myService")
    var another: AnotherService by ServiceDelegate("anotherService")
}

3.3 observable 自定义实现

kotlin
// 自定义 observable
class ObservableProperty<T>(
    private val initialValue: T,
    private val onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit
) : ReadWriteProperty<Any?, T> {
    
    private var value = initialValue
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        val oldValue = this.value
        this.value = value
        onChange(property, oldValue, value)
    }
}

// 使用
class User {
    var name: String by ObservableProperty("<no name>") { prop, old, new ->
        println("${prop.name} changed from $old to $new")
    }
}

// 多个观察者
class MultiObservableProperty<T>(
    private val initialValue: T
) : ReadWriteProperty<Any?, T> {
    
    private val observers = mutableListOf<(T, T) -> Unit>()
    private var value = initialValue
    
    fun addObserver(observer: (old: T, new: T) -> Unit) {
        observers.add(observer)
    }
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        val oldValue = this.value
        this.value = value
        observers.forEach { it(oldValue, value) }
    }
}

3.4 缓存委托

kotlin
// 缓存委托:首次计算后缓存结果
class CachedProperty<T>(
    private val compute: () -> T
) : ReadOnlyProperty<Any?, T> {
    
    private var cached: T? = null
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return cached ?: compute().also { cached = it }
    }
    
    fun invalidate() {
        cached = null
    }
}

// 使用
class Repository {
    val users: List<User> by CachedProperty {
        println("Loading users from database...")
        loadUsersFromDatabase()
    }
}

// 带过期时间的缓存
class TimedCachedProperty<T>(
    private val compute: () -> T,
    private val ttlMs: Long
) : ReadOnlyProperty<Any?, T> {
    
    private var cached: T? = null
    private var expireTime: Long = 0
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        val now = System.currentTimeMillis()
        if (cached == null || now > expireTime) {
            cached = compute()
            expireTime = now + ttlMs
        }
        return cached!!
    }
}

// 使用
class ApiService {
    val config: Config by TimedCachedProperty(
        compute = { fetchConfigFromServer() },
        ttlMs = 5 * 60 * 1000  // 5 分钟
    )
}

3.5 绑定委托

kotlin
// 双向绑定委托
class BindableProperty<T>(
    private val initialValue: T,
    private val onSet: (T) -> Unit
) : ReadWriteProperty<Any?, T> {
    
    private var value = initialValue
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
        onSet(value)
    }
}

// 使用:UI 绑定
class ViewModel {
    var text: String by BindableProperty("") { newText ->
        updateTextView(newText)
    }
    
    private fun updateTextView(text: String) {
        // 更新 UI
    }
}

// 计算属性委托
class ComputedProperty<T, R>(
    private val source: ReadWriteProperty<Any?, T>,
    private val compute: (T) -> R,
    private val reverse: (R) -> T
) : ReadWriteProperty<Any?, R> {
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): R {
        return compute(source.getValue(thisRef, property))
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: R) {
        source.setValue(thisRef, property, reverse(value))
    }
}

// 使用
class Temperature {
    private var celsius: Double by Delegates.observable(0.0) { _, _, _ ->
        println("Temperature changed")
    }
    
    var fahrenheit: Double by ComputedProperty(
        source = this::celsius,
        compute = { c -> c * 9 / 5 + 32 },
        reverse = { f -> (f - 32) * 5 / 9 }
    )
}

4. 委托属性原理

4.1 编译原理

委托属性在编译时被转换为委托对象的调用:

kotlin
// Kotlin 代码
class Example {
    var prop: String by Delegate()
}

class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "value"
    }
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        // ...
    }
}

// 编译后(伪代码)
class Example {
    private val delegate = Delegate()
    
    var prop: String
        get() = delegate.getValue(this, ::prop)
        set(value) = delegate.setValue(this, ::prop, value)
}

4.2 KProperty 参数

kotlin
// KProperty 提供属性元数据
import kotlin.reflect.KProperty

class LoggingDelegate<T> : ReadWriteProperty<Any?, T> {
    private var value: T? = null
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        println("Getting ${property.name}")
        return value as T
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        println("Setting ${property.name} to $value")
        this.value = value
    }
}

// KProperty 的常用属性
// - name: 属性名
// - returnType: 返回类型
// - annotations: 注解
// - isAbstract: 是否抽象
// - isFinal: 是否 final
// - isOpen: 是否 open

// 使用示例
class Example {
    var name: String by LoggingDelegate()
}

val example = Example()
example.name = "Kotlin"  // 打印:Setting name to Kotlin
println(example.name)     // 打印:Getting name

4.3 thisRef 参数

kotlin
// thisRef 是属性所属的对象实例
class Delegate : ReadWriteProperty<MyClass, String> {
    private var value: String = ""
    
    override fun getValue(thisRef: MyClass, property: KProperty<*>): String {
        // thisRef 是 MyClass 实例
        println("Getting from ${thisRef::class.simpleName}")
        return value
    }
    
    override fun setValue(thisRef: MyClass, property: KProperty<*>, value: String) {
        this.value = value
    }
}

class MyClass {
    var prop: String by Delegate()
}

// 使用 Any? 作为 thisRef 类型可以适用于任何类
class GenericDelegate<T> : ReadWriteProperty<Any?, T> {
    // ...
}

4.4 委托的线程安全

kotlin
// 线程安全的委托
class ThreadSafeDelegate<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
    private var value: T = initialValue
    private val lock = Any()
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        synchronized(lock) {
            return value
        }
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        synchronized(lock) {
            this.value = value
        }
    }
}

// 使用 volatile
class VolatileDelegate<T>(@Volatile private var value: T) : ReadWriteProperty<Any?, T> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}

// 使用 AtomicInteger 等原子类
class AtomicDelegate(initialValue: Int) : ReadWriteProperty<Any?, Int> {
    private val atomic = AtomicInteger(initialValue)
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
        return atomic.get()
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
        atomic.set(value)
    }
}

4.5 委托与继承

kotlin
// 委托可以被继承
open class Base {
    var name: String by Delegates.observable("") { _, old, new ->
        println("Base: $old -> $new")
    }
}

class Derived : Base() {
    // 继承 name 属性
}

// 使用
val derived = Derived()
derived.name = "Kotlin"  // 打印:Base:  -> Kotlin

// 重写委托属性
class Derived2 : Base() {
    override var name: String = ""
    // 不再使用委托
}

5. ReadWriteProperty/ReadOnlyProperty

5.1 接口定义

kotlin
// ReadOnlyProperty - 只读属性委托
public interface ReadOnlyProperty<in R, out T> {
    public operator fun getValue(thisRef: R, property: KProperty<*>): T
}

// ReadWriteProperty - 可读写属性委托
public interface ReadWriteProperty<in R, T> {
    public operator fun getValue(thisRef: R, property: KProperty<*>): T
    public operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}

5.2 实现 ReadOnlyProperty

kotlin
// 只读委托示例
class ConstantProperty<T>(private val value: T) : ReadOnlyProperty<Any?, T> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value
    }
}

// 使用
class Example {
    val pi: Double by ConstantProperty(3.14159)
    val e: Double by ConstantProperty(2.71828)
}

// 计算只读属性
class ComputedReadOnlyProperty<T>(
    private val compute: () -> T
) : ReadOnlyProperty<Any?, T> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return compute()
    }
}

// 使用
class MathConstants {
    val random: Double by ComputedReadOnlyProperty { Math.random() }
}

5.3 实现 ReadWriteProperty

kotlin
// 完整的可读写委托
class FullDelegate<T>(
    initialValue: T,
    private val onGet: (T) -> Unit = {},
    private val onSet: (T) -> Unit = {}
) : ReadWriteProperty<Any?, T> {
    
    private var value: T = initialValue
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        onGet(value)
        return value
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
        onSet(value)
    }
}

// 使用
class Example {
    var name: String by FullDelegate(
        initialValue = "",
        onGet = { println("Getting: $it") },
        onSet = { println("Setting: $it") }
    )
}

5.4 委托提供者(ProvideDelegate)

kotlin
// provideDelegate 在创建委托时调用
class ResourceProvider {
    operator fun provideDelegate(
        thisRef: MyActivity,
        property: KProperty<*>
    ): ReadOnlyProperty<MyActivity, View> {
        // 在创建委托时执行,可以用于查找 View
        val view = thisRef.findViewById<View>(getResourceId(property.name))
        return Property { _, _ -> view }
    }
    
    private fun getResourceId(name: String): Int {
        // 根据属性名获取资源 ID
        return 0
    }
}

class Property(
    private val value: View
) : ReadOnlyProperty<MyActivity, View> {
    override fun getValue(thisRef: MyActivity, property: KProperty<*>): View {
        return value
    }
}

// 使用
class MyActivity {
    val button: View by ResourceProvider()
    // provideDelegate 在初始化时调用
}

// 实际场景:ViewBinding
class ViewBindingDelegate<T : ViewBinding>(
    private val factory: (View) -> T
) : ReadOnlyProperty<Activity, T> {
    
    private var binding: T? = null
    
    override fun getValue(thisRef: Activity, property: KProperty<*>): T {
        return binding ?: factory(thisRef.window.decorView).also { binding = it }
    }
}

// 使用
class MyActivity : AppCompatActivity() {
    val binding: ActivityMainBinding by ViewBindingDelegate(ActivityMainBinding::inflate)
}

5.5 委托组合

kotlin
// 组合多个委托
class CompositeDelegate<T>(
    private val delegates: List<ReadWriteProperty<Any?, T>>
) : ReadWriteProperty<Any?, T> {
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return delegates.first().getValue(thisRef, property)
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        delegates.forEach { it.setValue(thisRef, property, value) }
    }
}

// 链式委托
class ChainDelegate<T>(
    private val readDelegate: ReadOnlyProperty<Any?, T>,
    private val writeDelegate: WriteOnlyProperty<Any?, T>
) : ReadWriteProperty<Any?, T> {
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return readDelegate.getValue(thisRef, property)
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        writeDelegate.setValue(thisRef, property, value)
    }
}

// WriteOnlyProperty(自定义)
interface WriteOnlyProperty<in R, in T> {
    operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}

6. 面试考点汇总

6.1 基础问题

Q1: 什么是委托属性?如何使用?

kotlin
// 答案要点:
// 1. 将属性的 getter/setter 委托给另一个对象
// 2. 使用 by 关键字
// 3. 委托类需要实现 getValue/setValue
// 4. 标准库提供 lazy、observable 等委托

// 定义
class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "value"
    }
}

// 使用
class Example {
    var prop: String by Delegate()
}

Q2: lazy 委托的原理是什么?

kotlin
// 答案要点:
// 1. 返回 Lazy<T> 接口
// 2. 首次访问时执行初始化 lambda
// 3. 结果被缓存
// 4. 三种线程安全模式

val value: String by lazy {
    println("Computing...")
    "Hello"
}
// 第一次访问:打印 "Computing..." 然后 "Hello"
// 后续访问:只返回 "Hello"

Q3: observable 和 vetoable 的区别?

kotlin
// 答案要点:
// 1. observable:属性变化后通知
// 2. vetoable:可以拒绝属性更新
// 3. observable 返回 Unit
// 4. vetoable 返回 Boolean

// observable
var name by Delegates.observable("") { _, old, new ->
    println("Changed from $old to $new")
}

// vetoable
var age by Delegates.vetoable(0) { _, _, new ->
    new >= 0  // 拒绝负数
}

6.2 进阶问题

Q4: 如何自定义委托属性?

kotlin
// 答案要点:
// 1. 实现 ReadWriteProperty 或 ReadOnlyProperty
// 2. 实现 getValue 和 setValue 方法
// 3. 使用 by 关键字应用委托

class NotNullVar<T> : ReadWriteProperty<Any?, T> {
    private var value: T? = null
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value ?: throw IllegalStateException("Not initialized")
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}

Q5: 委托属性的编译原理?

kotlin
// 答案要点:
// 1. 编译时创建委托对象实例
// 2. getter 转换为 delegate.getValue(this, ::prop)
// 3. setter 转换为 delegate.setValue(this, ::prop, value)
// 4. KProperty 提供属性元数据

// Kotlin
class Example {
    var prop: String by Delegate()
}

// 编译后(伪代码)
class Example {
    private val delegate = Delegate()
    
    var prop: String
        get() = delegate.getValue(this, ::prop)
        set(value) = delegate.setValue(this, ::prop, value)
}

Q6: provideDelegate 的作用?

kotlin
// 答案要点:
// 1. 在创建委托时调用
// 2. 可以返回不同的委托对象
// 3. 用于 ViewBinding 等场景
// 4. 操作符函数 provideDelegate

class ResourceProvider {
    operator fun provideDelegate(
        thisRef: Activity,
        property: KProperty<*>
    ): ReadOnlyProperty<Activity, View> {
        val view = thisRef.findViewById(property.name)
        return Property { _, _ -> view }
    }
}

6.3 原理问题

Q7: lazy 的三种线程安全模式?

kotlin
// 答案要点:
// 1. SYNCHRONIZED:默认,使用锁,线程安全
// 2. PUBLICATION:可能多次计算,但返回相同结果
// 3. NONE:单线程,无锁,最快

val lazy1 by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { compute() }
val lazy2 by lazy(LazyThreadSafetyMode.PUBLICATION) { compute() }
val lazy3 by lazy(LazyThreadSafetyMode.NONE) { compute() }

Q8: 委托属性的内存开销?

kotlin
// 答案要点:
// 1. 每个委托属性创建委托对象
// 2. 有额外的对象分配
// 3. lazy 委托只创建一次
// 4. observable 委托持有观察者引用

// 内存考虑
class Example {
    // 每个实例都创建 Delegate 对象
    var prop: String by Delegate()
    
    // 可以使用伴生对象共享
    companion object {
        private val delegate = Delegate()
    }
    var prop2: String by delegate
}

6.4 实战问题

Q9: 如何在 Android 中使用委托属性?

kotlin
// 答案要点:
// 1. lazy 用于延迟初始化
// 2. observable 用于 UI 绑定
// 3. map 用于参数解析
// 4. 自定义委托用于 ViewBinding

// lazy
class Repository {
    private val database: Database by lazy {
        Database.connect()
    }
}

// observable
class ViewModel {
    var userName: String by Delegates.observable("") { _, _, _ ->
        notifyUiChanged()
    }
}

// map
class Fragment : Fragment() {
    val userId: String by arguments!!
}

// ViewBinding
class Activity : AppCompatActivity() {
    val binding: ActivityMainBinding by ViewBindingDelegate()
}

Q10: 委托属性与 lateinit 的区别?

kotlin
// 答案要点:
// 1. lateinit 用于 var,不能用于 val
// 2. lateinit 不能用于基本类型
// 3. lateinit 在赋值前访问抛异常
// 4. 委托更灵活,可以自定义行为

// lateinit
lateinit var view: View

// 委托
var view: View by NotNullVar()
val config: Config by lazy { Config() }

Q11: 如何实现线程安全的委托?

kotlin
// 答案要点:
// 1. 使用 synchronized
// 2. 使用 volatile
// 3. 使用原子类
// 4. 使用 lazy 的 SYNCHRONIZED 模式

class ThreadSafeDelegate<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
    private var value: T = initialValue
    private val lock = Any()
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        synchronized(lock) { return value }
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        synchronized(lock) { this.value = value }
    }
}

最佳实践总结

✅ 推荐做法

kotlin
// 1. 使用 lazy 延迟初始化
val database: Database by lazy { Database.connect() }

// 2. 使用 observable 监听变化
var name by Delegates.observable("") { _, old, new ->
    println("Changed: $old -> $new")
}

// 3. 使用 vetoable 验证
var age by Delegates.vetoable(0) { _, _, new -> new >= 0 }

// 4. 使用 map 解析参数
class User(map: Map<String, Any?>) {
    val name: String by map
}

// 5. 自定义委托复用逻辑
class NotNullVar<T> : ReadWriteProperty<Any?, T> { ... }

❌ 避免做法

kotlin
// 1. 避免过度使用委托
// 不是所有属性都需要委托

// 2. 避免复杂的委托逻辑
// 委托应该简单明了

// 3. 注意内存泄漏
// observable 持有观察者引用

// 4. 注意线程安全
// 多线程环境使用同步

参考资料


最后更新:2026-04-14