Kotlin Vocabulary | Kotlin 内建代理
lazy()
lazy() https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/lazy.html#kotlin$lazy(kotlin.Function0((kotlin.lazy.T)))
1<!-- Copyright 2020 Google LLC.
2SPDX-License-Identifier: Apache-2.0 -->
3
4class Person(name: String, lastname: String) {
5 val fullname: String by lazy() {
6 name + lastname
7 }
8 //…
9}
内部原理
在查看反编译后的 Java 代码时,我们可以看到 Kotlin 编译器为惰性 (lazy) 代理创建了一个 Lazy 类型的引用:
1<!-- Copyright 2020 Google LLC.
2SPDX-License-Identifier: Apache-2.0 -->
3
4@NotNull
5private final Lazy fullname$delegate;
这一代理通过调用 LazyKt.lazy() 函数,并传入您定义的 lambda 表达式与线程安全模式参数来进行初始化:
1<!-- Copyright 2020 Google LLC.
2SPDX-License-Identifier: Apache-2.0 -->
3
4 this.fullname$delegate = LazyKt.lazy((Function0)(new Function0() {
5 @NotNull
6 public final String invoke() {
7 return name + lastname;
8 }
9 }));
lazy()
https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/kotlin/util/Lazy.kt
1public actual fun <T> lazy(initializer: () -> T): Lazy<T> =
2 SynchronizedLazyImpl(initializer)
1override val value: T
2 get() {
3 val _v1 = _value
4 if (_v1 !== UNINITIALIZED_VALUE) {
5 @Suppress("UNCHECKED_CAST")
6 return _v1 as T
7 }
8
9 return synchronized(lock) {
10 val _v2 = _value
11 if (_v2 !== UNINITIALIZED_VALUE) {
12 @Suppress("UNCHECKED_CAST") (_v2 as T)
13 } else {
14 val typedValue = initializer!!()
15 _value = typedValue
16 initializer = null
17 typedValue
18 }
19 }
20 }
注意: 如果您确定资源会在单线程中被初始化,您可以向 lazy() 传入 LazyThreadSafetyMode.NONE,这样函数就不会在惰性初始化时使用 synchronized 块。不过请记住,LazyThreadSafetyMode.NONE 不会改变惰性初始化的同步特性。由于惰性初始化是同步的,所以在第一次访问时仍会消耗与非惰性初始化过程相同的时间,这意味着那些初始化过程较为耗时的对象仍会在被访问时阻塞 UI 线程。 1val lazyValue: String by lazy(LazyThreadSafetyMode.NONE) {“lazy”}
Observable
Delegates.observable() 是另一个 Kotlin 标准库中内建的代理。观察者模式是一种设计模式,在这一模式中,一个对象会维护一个它的从属者的列表,这些从属者即被称为观察者。对象会在它自己的状态改变时对观察者进行通知。这一模式十分契合多个对象需要在某个值发生改变时得到通知的情况,可以避免实现为从属对象周期调用和检查资源是否更新。
Delegates.observable()
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.properties/-delegates/observable.html
ObservableProperty
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.properties/-observable-property/
1<!-- Copyright 2020 Google LLC.
2SPDX-License-Identifier: Apache-2.0 -->
3
4class Person {
5 var address: String by Delegates.observable("not entered yet!") {
6 property, oldValue, newValue ->
7 // 执行更新操作
8 }
9}
ObservableProperty
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.properties/-observable-property/
1<!-- Copyright 2020 Google LLC.
2SPDX-License-Identifier: Apache-2.0 -->
3
4protected void afterChange(@NotNull KProperty property, Object oldValue, Object newValue) {
5 // 执行更新操作
6}
afterChange() 函数由父 ObservableProperty 类的 setter 调用,这意味着每当调用者为 address 设置一个新的值,setter 就会自动调用 afterChange() 函数,结果就会使所有的监听器都会收到有关改变的通知。
1<!-- Copyright 2020 Google LLC.
2SPDX-License-Identifier: Apache-2.0 -->
3
4public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
5 val oldValue = this.value
6 if (!beforeChange(property, oldValue, value)) {
7 return
8 }
9 this.value = value
10 afterChange(property, oldValue, value)
11}
vetoable
vetoable()
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.properties/-delegates/vetoable.html
1<!-- Copyright 2020 Google LLC.
2SPDX-License-Identifier: Apache-2.0 -->
3
4var address: String by Delegates.vetoable("") {
5 property, oldValue, newValue ->
6 newValue.length > 14
7}
观察反编译后的 Person 可以发现,Kotlin 新生成了一个继承 ObservableProperty 的类,该类中包含了我们传入 beforeChange() 函数的 lambda 表达式,setter 会在每次值被设置之前调用 lambda 表达式。
1<!-- Copyright 2020 Google LLC.
2SPDX-License-Identifier: Apache-2.0 -->
3
4public final class Person$$special$$inlined$vetoable$1 extends ObservableProperty {
5
6 protected boolean beforeChange(@NotNull KProperty property, Object oldValue, Object newValue) {
7 Intrinsics.checkParameterIsNotNull(property, "property");
8 String newValue = (String)newValue;
9 String var10001 = (String)oldValue;
10 int var7 = false;
11 return newValue.length() > 14;
12 }
13}
notNull
Kotlin 标准库中所提供的最后一个内建代理是 Delegates.notNull()。notNull() 允许一个属性可以延后一段时间初始化,与 lateinit 类似。由于 notNull() 会为每个属性创建额外的对象,所以大多数情况下推荐使用 lateinit。不过,您可以将 notNull() 与原生类型一同使用,这点是 lateinit 所不支持的。
Delegates.notNull()
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.properties/-delegates/not-null.htmllateinit
https://kotlinlang.org/docs/reference/properties.html#late-initialized-properties-and-variables
1val fullname: String by Delegates.notNull<String>()
我们可以查看反编译后的代码,下面的例子中使用 notNull() 函数初始化了 fullname 属性:
1this.fullname$delegate = Delegates.INSTANCE.notNull();
该函数返回了一个 NotNullVar 对象:
1public fun <T : Any> notNull(): ReadWriteProperty<Any?, T> = NotNullVar()
NotNullVar 类型持有一个泛型的可空内部引用,如果在初始化值之前有任何代码调用 getter,则抛出 IllegalStateException()。
1<!-- Copyright 2020 Google LLC.
2SPDX-License-Identifier: Apache-2.0 -->
3
4private class NotNullVar<T : Any>() : ReadWriteProperty<Any?, T> {
5 private var value: T? = null
6
7 public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
8 return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
9 }
10
11 public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
12 this.value = value
13 }
14}
有了 Kotlin 标准库提供的这组内建代理,您无需再编写、维护与重新发明这些功能。这些内建代理可以帮您惰性初始化字段、允许原生类型延迟加载、监听并在值发生改变时获得通知,甚至可以否决属性值更改。
推荐阅读