代理可以帮助您将任务委托给其他对象,从而带来更佳的代码复用性。Kotlin 不仅可以让您通过 by 关键字轻松实现代理,还在标准库中提供了像 lazy()、observable()、vetoable() 以及 notNull() 这样的内建代理。接下来就让我们开始了解这些内建代理的使用,以及其内部的实现原理。
lazy()
lazy()函数是一个属性代理,它可以帮您在第一次访问属性时对它们进行惰性初始化。这个函数在创建昂贵对象时十分有用。
lazy()
函数接收两个参数,LazyThreadSafetyMode
枚举值与一个 lambda 表达式。
LazyThreadSafetyMode
用于指定初始化过程如何在不同线程间进行同步,它的默认值是 LazyThreadSafetyMode.SYNCHRONIZED
。这意味着初始化操作是线程安全的,但代价是显式同步会对性能造成轻微影响。
lambda 表达式会在属性第一次被访问时执行,而它的值将会被存储以用于接下来的访问。
class Person(name: String, lastname: String) {
val fullname: String by lazy() {
name + lastname
}
//…
}
内部原理
在查看反编译后的 Java 代码时,我们可以看到 Kotlin 编译器为惰性 (lazy) 代理创建了一个 Lazy 类型的引用:
@NotNull
private final Lazy fullname$delegate;
这一代理通过调用 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 <T> lazy(initializer: () -> T): Lazy<T> =