原文內(nèi)容來自 Kotlin - Property initialization using “by lazy” vs. “l(fā)ateinit”
lazy { ... } delegate can only be used for val properties, whereas lateinit can only be applied to vars, because it can't be compiled to a final field, thus no immutability can be guaranteed;
-
lazy { ... }
只能被用在被val
修飾的變量上,而lateinit
只能被用var
修飾的變量上剥险,因?yàn)楸?code>lateinit修飾的字段無法被編譯為一個final
字段、因此無法保證它的不可變性基显。
lateinit var has a backing field which stores the value, and by lazy { ... } creates a delegate object in which the value is stored once calculated, stores the reference to the delegate instance in the class object and generates the getter for the property that works with the delegate instance. So if you need the backing field present in the class, use lateinit
- 被
lateinit
修飾的變量有一個幕后字段用來存儲它的值椭员,而by lazy { ... }
創(chuàng)建了一個包含by lazy { ... }
中代碼返回值的實(shí)例對象雨涛,實(shí)例對象持有這個值并生成一個可以在實(shí)例對象中調(diào)用的這個值的getter
。所以如果你需要在代碼中使用幕后字段的話赶么,使用lateinit
In addition to vals, lateinit cannot be used for nullable properties and Java primitive types (this is because of null used for uninitialized value)
- 除了被
val
修飾的變量外肩豁,lateinit
也不能被用來修飾可空的屬性和java的基本類型(因?yàn)閷τ诳煽疹愋停瑫心J(rèn)值null
)
lateinit var can be initialized from anywhere the object is seen from, e.g. from inside a framework code, and multiple initialization scenarios are possible for different objects of a single class. by lazy { ... }, in turn, defines the only initializer for the property, which can be altered only by overriding the property in a subclass. If you want your property to be initialized from outside in a way probably unknown beforehand, use lateinit
- 被
lateinit
修飾的變量可以在對象(代碼)的任何地方進(jìn)行初始化辫呻,而且同一個類的不同對象可以對這個變量進(jìn)行多次的初始化(賦值)清钥。但是,對于by lazy { ... }
修飾的變量,只擁有唯一一個聲明在{}
中的初始化構(gòu)造器放闺,如果你想要修改它祟昭,你只能通過在子類中覆寫的方式來修改它的值。所以怖侦,如果你想要你的屬性在其他地方以不是你事先定義好的值初始化的話篡悟,使用lateinit
Initialization
by lazy { ... }
is thread-safe by default and guarantees that the initializer is invoked at most once (but this can be altered by using anotherlazy
overload). In case oflateinit var
, it's up to the user's code to initialize the property correctly in multi-threaded environments.
-
by lazy { ... }
的初始化默認(rèn)是線程安全的,并且能保證by lazy { ... }
代碼塊中的代碼最多被調(diào)用一次匾寝。而lateinit var
默認(rèn)是不保證線程安全的搬葬,它的情況完全取決于使用者的代碼。
A Lazy instance can be saved, passed around and even used for multiple properties. On contrary, lateinit vars do not store any additional runtime state (only null in the field for uninitialized value).
-
Lazy
實(shí)例是有值的艳悔,這個值可以被存儲急凰、傳遞和使用。但是很钓,被lateinit var
修飾的變量不存儲任何多余的運(yùn)行時(shí)狀態(tài)香府,只有值還未被初始化的null
值。
If you hold a reference to an instance of
Lazy
,isInitialized()
allows you to check whether it has already been initialized (and you can obtain such instance with reflection from a delegated property). To check whether a lateinit property has been initialized, you can useproperty::isInitialized
since Kotlin 1.2.
- 如果你持有一個
Lazy
實(shí)例的引用码倦,你可以使用它的isInitialized()
方法來判斷它是否已經(jīng)被初始化。從Kotlin1.2開始锭碳,你也可以使用方法引用的方式來獲取這個值袁稽。
A lambda passed to
by lazy { ... }
may capture references from the context where it is used into its closure.. It will then store the references and release them only once the property has been initialized. This may lead to object hierarchies, such as Android activities, not being released for too long (or ever, if the property remains accessible and is never accessed), so you should be careful about what you use inside the initializer lambda.
-
by lazy { ... }
中傳遞的lambda表達(dá)式可能會捕獲它的閉包中使用的上下文的引用,引用會一直被持有直到變量被初始化擒抛。因此這樣可能會導(dǎo)致內(nèi)存泄漏推汽,所以仔細(xì)考慮你在lambda表達(dá)式中使用的值是否合理