编译器生成的字节码:
class Example {
private val prop$delegate = Delegate()
// 被委托属性
var prop: String
get() = prop$delegate.getValue(this, this:prop)
set(value : String) = prop$delegate.setValue(this, this:prop, value)
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| > **注意事项:** > - thisRef —— 必须与属性所有者类型相同或者是它的超类型。 > - property —— 必须是类型 KProperty<*> 或其超类型。 > - value —— 必须和属性同类型或者是它的超类型。
### 局部变量委托 局部变量也可以声明委托,例如: ```kotlin fun main(args: Array<String>) { val lazyValue: String by lazy { println("Lazy Init Completed!") "Hello World." } if (true/*someCondition*/) { println(lazyValue) // 首次调用 println(lazyValue) // 后续调用 } } 输出: Lazy Init Completed! Hello World. Hello World.
|
Kotlin 委托进阶
延迟属性委托 lazy
lazy 是一个标准库函数,参数为一个 Lambda 表达式,返回值为一个 Lazy 实例,使用 lazy 可以实现延迟属性委托,在委托对象比较耗资源的场景会非常有用。首次访问属性是,会执行 lazy 函数的 lambda 表达式并将结果记录到「背域」,后续调用 getter() 方法只是直接返回「背域」的值。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| val lazyValue: String by lazy { println("Lazy Init Completed!") "Hello World." }
fun main(args: Array<String>) { println(lazyValue) println(lazyValue) }
输出: Lazy Init Completed! Hello World. Hello World.
|
可观察属性 ObservableProperty
使用 Delegates.observable() 可以实现可观察属性,函数接受两个参数:第一个参数为初始值,第二个参数为属性值变化的回调。函数的返回值是 ObservableProperty 可观察属性,它在调用 setValue(…) 是触发回调。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class User { var name: String by Delegates.observable("初始值") { prop, old, new -> println("旧值:$old -> 新值:$new") } }
fun main(args: Array<String>) { val user = User() user.name = "第一次赋值" user.name = "第二次赋值" }
输出: 旧值:初始值 -> 新值:第一次赋值 旧值:第一次赋值 -> 新值:第二次赋值
|
使用 Map 存储属性值
Map / MutableMap 也可以用来实现属性委托,从而此时字段名是 Key,属性值是 Value。例如;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class User(val map: Map<String, Any?>) { val name: String by map }
fun main(args: Array<String>) { val map = mutableMapOf( "name" to "彭" ) val user = User(map) println(user.name) map["name"] = "peng" println(user.name) } 输出: 彭 peng
|
4. 总结
Kotlin 委托的语法关键字是 by,其本质上是面向编译器的语法糖,三种委托(类委托、对象委托和局部变量委托)在编译时都会转化为 “无糖语法”。例如类委托:编译器会实现基础接口的所有方法,并直接委托给基础对象来处理。例如对象委托和局部变量委托:在编译时会生成辅助属性(prop$degelate),而属性 / 变量的 getter() 和 setter() 方法只是简单地委托给辅助属性的 getValue() 和 setValue() 处理。