属于Kotlin中的委托属性这一章中的标准委托
延迟属性Lazy
lazy()
是接受一个lambda
并返回一个 Lazy <T>
实例的函数,返回的实例可以作为实现延迟属性的委托。也就是说:
第一次调用get()
会执行已传递给 lazy()
的 lambda 表达式并记录结果, 后续调用get()
只是返回记录的结果。
这里需要注意的是 调用的是
get()
方法,和set没啥关系
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
输出结果为
computed!
Hello
Hello
同步锁模式
防止对个线程同时初始化
默认情况下,对于 lazy
属性的求值是同步锁的(synchronized):该值只在一个线程中计算,并且所有线程会看到相同的值。如果初始化委托的同步锁不是必需的,这样多个线程可以同时执行,那么将 LazyThreadSafetyMode.PUBLICATION
作为参数传递给 lazy() 函数。 而如果你确定初始化将总是发生在单个线程,那么你可以使用 LazyThreadSafetyMode.NONE
模式, 它不会有任何线程安全的保证和相关的开销。
延迟属性Lazy 与 lateinit 区别
以下是lateinit var和by lazy { ... }委托属性之间的显著差异:
-
lazy { ... }
代表只能用于val
属性,而lateinit
只能用于var
,因为它不能编译到final字段,因此不能保证不变性; -
lateinit var
具有存储值的后备字段(backing field)
,而by lazy { ... }
创建一个委托对象,其中存储一次计算的值,将对代理实例的引用存储在类对象中,并为与委托实例一起使用的属性生成getter。 - 除了val之外,
lateinit
不能用于可空属性和Java原语类型(这是因为null用于未初始化的值);所以如果你需要在类中存在的支持字段,请使用lateinit;
lateinit var
可以从对象被看到的任何地方被初始化。从一个框架代码的内部,多个初始化方案是可能的单一类的不同对象。by lazy { ... }
反过来又定义了属性的唯一初始化器,只能通过覆盖子类中的属性进行更改。如果您希望以预先未知的方式从外部初始化属性,请使用lateinit。 - 另外,还有一个方法没有提到Delegates.notNull(),它适用于non-null属性的延迟初始化,包括Java原始类型的属性。
延迟属性Lazy 与 lateinit 使用总结
lateinit
用于外部初始化:当需要外部资料通过调用方法初始化您的值时。
例如通过调用:
private lateinit var value: MyClass
fun init(externalProperties: Any) {
value = somethingThatDependsOn(externalProperties)
}
而lazy
当它只使用对象内部的依赖关系时。
嗯。静态变量的初始化挺适合这种方式的。
网友评论