Kotlin Vocabulary

Kotlin Vocabulary,第1张

Kotlin Vocabulary

这一代理通过调用 LazyKt.lazy() 函数,并传入您定义的 lambda 表达式与线程安全模式参数来进行初始化:

this.fullname$delegate = LazyKt.lazy((Function0)(new Function0() {
@NotNull
public final String invoke() {
return name + lastname;
}
}));

让我们来观察 lazy() 的源码。由于 lazy() 函数默认使用 LazyThreadSafetyMode.SYNCHRONIZED 参数,因此它将返回一个 SynchronizedLazyImpl
类型的 Lazy 对象:

public actual fun lazy(initializer: () -> T): Lazy =
SynchronizedLazyImpl(initializer)

当属性代理第一次被访问时,SynchronizedLazyImpl 的 getValue() 函数就会被调用,这个函数将会在一个 synchronized 块中对属性进行初始化:

override val value: T
get() {
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress(“UNCHECKED_CAST”)
return _v1 as T
}

return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
@Suppress(“UNCHECKED_CAST”) (_v2 as T)
} else {
val typedValue = initializer!!()
_value = typedValue
initializer = null
typedValue
}
}
}

这样就能保证惰性对象会以线程安全的方式初始化,但同时也引入了由 synchronized 块带来的额外开销。

注意: 如果您确定资源会在单线程中被初始化,您可以向 lazy() 传入 LazyThreadSafetyMode.NONE,这样函数就不会在惰性初始化时使用 synchronized 块。不过请记住,LazyThreadSafetyMode.NONE 不会改变惰性初始化的同步特性。由于惰性初始化是同步的,所以在第一次访问时仍会消耗与非惰性初始化过程相同的时间,这意味着那些初始化过程较为耗时的对象仍会在被访问时阻塞 UI 线程。

1val lazyValue: String by lazy(LazyThreadSafetyMode.NONE) {“lazy”}

惰性初始化可以帮助初始化昂贵资源,但对于诸如 String 一类的简单对象,由于 lazy() 函数需要生成 Lazy 和 KProperty 这样的额外对象,反而会增加整个过程的开销。

Observable

Delegates.observable() 是另一个 Kotlin 标准库中内建的代理。观察者模式是一种设计模式,在这一模式中,一个对象会维护一个它的从属者的列表,这些从属者即被称为观察者。对象会在它自己的状态改变时对观察者进行通知。这一模式十分契合多个对象需要在某个值发生改变时得到通知的情况,可以避免实现为从属对象周期调用和检查资源是否更新。

observable() 函数接收两个参数: 初始化值与一个当值发生改变时会被调用的监听处理器。observable() 会创建一个 ObservableProperty 对象,用于在每次 setter 被调用时执行您传给代理的 lambda 表达式。

class Person {
var address: String by Delegates.observable(“not entered yet!”) {
property, oldValue, newValue ->
// 执行更新 *** 作
}
}

通过观察反编译后的 Person 类型,我们可以看到 Kotlin 编译器生成了一个继承 ObservableProperty 的类。这个类同时也实现了一个叫做 afterChange() 的函数,这个函数持有您传递给 observable 代理的 lambda 函数。

protected void afterChange(@NotNull KProperty property, Object oldValue, Object newValue) {
// 执行更新 *** 作
}

afterChange() 函数由父 ObservableProperty 类的 setter 调用,这意味着每当调用者为 address 设置一个新的值,setter 就会自动调用 afterChange() 函数,结果就会使所有的监听器都会收到有关改变的通知。

class Person {
var address: String by Delegates.observable(“not entered yet!”) {
property, oldValue, newValue ->
// 执行更新 *** 作
}
}

您还可以从反编译后的代码中看到 beforeChange() 函数的调用,observable 代理不会使用 beforeChange()。但对于您接下来会看到的 vetoable(),这一函数却是功能实现的基础。

vetoable

vetoable() 是一个内建代理,属性将否决权委托给它的值。与 observable() 代理类似,vetoable() 同样接受两个参数: 初始值与监听器,当任何调用者想要修改属性值时,监听器就会被调用。

var address: String by Delegates.vetoable("") {
property, oldValue, newValue ->
newValue.length > 14
}

如果 lambda 表达式返回 true,属性值就会被修改,反之则保持不变。在本例中,如果调用者尝试使用长度小于 15 个字符的字符串来更新地址的话,当前值就不会发生改变。

观察反编译后的 Person 可以发现,Kotlin 新生成了一个继承 ObservableProperty 的类,该类中包含了我们传入 beforeChange() 函数的 lambda 表达式,setter 会在每次值被设置之前调用 lambda 表达式。

public final class Person s p e c i a l special specialinlined$vetoable$1 extends ObservableProperty {

protected boolean beforeChange(@NotNull KProperty property, Object oldValue, Object newValue) {
1 extends ObservableProperty {

protected boolean beforeChange(@NotNull KProperty property, Object oldValue, Object newValue) {

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5708534.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存