屬于Kotlin中的委托屬性這一章中的標(biāo)準(zhǔn)委托
延遲屬性Lazy
lazy()
是接受一個(gè)lambda
并返回一個(gè) Lazy <T>
實(shí)例的函數(shù),返回的實(shí)例可以作為實(shí)現(xiàn)延遲屬性的委托遭赂。也就是說(shuō):
第一次調(diào)用get()
會(huì)執(zhí)行已傳遞給 lazy()
的 lambda 表達(dá)式并記錄結(jié)果库说, 后續(xù)調(diào)用get()
只是返回記錄的結(jié)果巷挥。
這里需要注意的是 調(diào)用的是
get()
方法,和set沒(méi)啥關(guān)系
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
輸出結(jié)果為
computed!
Hello
Hello
同步鎖模式
防止對(duì)個(gè)線程同時(shí)初始化
默認(rèn)情況下,對(duì)于 lazy
屬性的求值是同步鎖的(synchronized):該值只在一個(gè)線程中計(jì)算,并且所有線程會(huì)看到相同的值食呻。如果初始化委托的同步鎖不是必需的友雳,這樣多個(gè)線程可以同時(shí)執(zhí)行稿湿,那么將 LazyThreadSafetyMode.PUBLICATION
作為參數(shù)傳遞給 lazy() 函數(shù)。 而如果你確定初始化將總是發(fā)生在單個(gè)線程押赊,那么你可以使用 LazyThreadSafetyMode.NONE
模式饺藤, 它不會(huì)有任何線程安全的保證和相關(guān)的開(kāi)銷。
延遲屬性Lazy 與 lateinit 區(qū)別
以下是lateinit var和by lazy { ... }委托屬性之間的顯著差異:
-
lazy { ... }
代表只能用于val
屬性流礁,而lateinit
只能用于var
涕俗,因?yàn)樗荒芫幾g到final字段,因此不能保證不變性; -
lateinit var
具有存儲(chǔ)值的后備字段(backing field)
神帅,而by lazy { ... }
創(chuàng)建一個(gè)委托對(duì)象再姑,其中存儲(chǔ)一次計(jì)算的值,將對(duì)代理實(shí)例的引用存儲(chǔ)在類對(duì)象中找御,并為與委托實(shí)例一起使用的屬性生成getter元镀。 - 除了val之外谜嫉,
lateinit
不能用于可空屬性和Java原語(yǔ)類型(這是因?yàn)閚ull用于未初始化的值);所以如果你需要在類中存在的支持字段,請(qǐng)使用lateinit;
lateinit var
可以從對(duì)象被看到的任何地方被初始化凹联。從一個(gè)框架代碼的內(nèi)部沐兰,多個(gè)初始化方案是可能的單一類的不同對(duì)象。by lazy { ... }
反過(guò)來(lái)又定義了屬性的唯一初始化器蔽挠,只能通過(guò)覆蓋子類中的屬性進(jìn)行更改住闯。如果您希望以預(yù)先未知的方式從外部初始化屬性,請(qǐng)使用lateinit澳淑。 - 另外比原,還有一個(gè)方法沒(méi)有提到Delegates.notNull(),它適用于non-null屬性的延遲初始化杠巡,包括Java原始類型的屬性量窘。
延遲屬性Lazy 與 lateinit 使用總結(jié)
lateinit
用于外部初始化:當(dāng)需要外部資料通過(guò)調(diào)用方法初始化您的值時(shí)。
例如通過(guò)調(diào)用:
private lateinit var value: MyClass
fun init(externalProperties: Any) {
value = somethingThatDependsOn(externalProperties)
}
而lazy
當(dāng)它只使用對(duì)象內(nèi)部的依賴關(guān)系時(shí)氢拥。
嗯蚌铜。靜態(tài)變量的初始化挺適合這種方式的。