Kotlin的lazy属性委托可以实现对属性的懒加载,但是只能使用于不可变属性,当属性需要重新加载时即无法使用,编写了一个resettablelazy,在满足懒加载的同时,也能在适当时机对属性进行重置,让属性在重置后的下次调用重新加载
基本概念
by关键字在kotlin中称为属性委托,指将某个属性托付给一个代理类进行实现,这个属性的get和set方法由代理类的getValue()和setValue()方法
kotlin官方文档中的委托属性的相的模板:
import kotlin.reflect.KProperty
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}
再进入kotlin的源码查看lazy的具体实现
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
可以看到lazy返回了一个SynchronizedLazyImpl类的对象,进入SynchronizedLazyImpl:
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
// final field is required to enable safe publication of constructed instance
private val lock = lock ?: this
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
}
}
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
在SynchronizedLazyImpl中有一个不可变属性value,在value的get方法中通过判断保持返回对象的唯一性
结合使用lazy,即保持lazy的线程安全特性也保证了可重置
代码:
class ResettableLazy<PROPTYPE>(val init: () -> PROPTYPE) {
var lazyHolder = makeInitBlock()
operator fun getValue(thisRef: Any?, property: KProperty<*>): PROPTYPE {
return lazyHolder.value
}
fun isInitialized(): Boolean {
return lazyHolder.isInitialized()
}
fun reset() {
lazyHolder = makeInitBlock()
}
fun makeInitBlock(): Lazy<PROPTYPE> {
return lazy {
init()
}
}
}
fun <PROPTYPE> resettableLazy(init: () -> PROPTYPE): ResettableLazy<PROPTYPE> {
return ResettableLazy(init)
}
使用
使用时还是使用by
eg:
private val sdfLazy = resettableLazy {
SimpleDateFormat.getDateTimeInstance(
SimpleDateFormat.MEDIUM, SimpleDateFormat.SHORT, Locale.getDefault())
}
private val sdf: DateFormat by sdf1Lazy
重置调用调用托管类的reset方法:
sdf1Lazy.reset()