延迟属性Lazy
下面是一个标准的延迟加载的方法。
class Person{
val name: String by lazy {
println("computed!")
"2357"
}
val age: Int by lazy {
println("init age!")
90
}
}
fun main() {
var person = Person();
println(person.name)
println(person.name)
println(person.age)
}
运行结果
computed!
2357
2357
init age!
25
第一次调用的时候会执行lazy{}中的代码块,但是到了第二次调用的时候就是直接使用这个值。
我们转成java方法看一下实现。
public final class LazyValueKt {
public static final void main() {
Person person = new Person();
String var1 = person.getName();
boolean var2 = false;
System.out.println(var1);
var1 = person.getName();
var2 = false;
System.out.println(var1);
int var3 = person.getAge();
var2 = false;
System.out.println(var3);
}
//main方法基本上没有变化
public static void main(String[] var0) {
main();
}
}
public final class Person {
@NotNull
private final Lazy name$delegate;
@NotNull
private final Lazy age$delegate;
//为代理属性增加了get方法。
@NotNull
public final String getName() {
Lazy var1 = this.name$delegate;
Object var3 = null;
boolean var4 = false;
return (String)var1.getValue();
}
public final int getAge() {
Lazy var1 = this.age$delegate;
Object var3 = null;
boolean var4 = false;
return ((Number)var1.getValue()).intValue();
}
public Person() {
//这里会给代理对象生成一个Lazy对象,这里是SynchronizedLazyImpl
//会把lazy{}中的初始haul方法作为参数传进去。
this.name$delegate = LazyKt.lazy((Function0)null.INSTANCE);
this.age$delegate = LazyKt.lazy((Function0)null.INSTANCE);
}
}
可以看到的是给每一个延迟加载属性增加了getXX方法,而且给每一个代理属性生成了代理对象,实际获取属性值都是给代理对象的getValue()方法来处理。
这里重点看一下lazy函数。
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
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)
}
lazy()是一个高阶函数,它接受一个initializer函数作为参数,这个initializer函数就是我们在使用标准委托时在lazy{...}中的代码。lazy()返回的是lazy对象(SynchronizedLazyImpl()),lazy对象中保存一个initializer属性。可以看到lazy对象(SynchronizedLazyImpl)中有一个没有初始化的 __value对象。在lazy对象的get方法中如果_value已经初始化,那就直接返回结果,如果没有初始化,就进入同步代码块,在同步代码块中,如果已经初始化,就直接返回,如果没有初始化,就调用lazy中的一个函数得到初始化结果,然后保存初始化后的值并返回该值。
by lazy{...} 提供了标准的属性延迟加载功能。核心还是在编译过程中自动增加了延迟加载的相关代码。
编译器会自动为每一个延迟的属性生成一个lazyImpl, 在对应的属性get函数中调用对应的lazyImpl的getValue()方法。
SynchronizedLazyImpl是已经实现好的,如果属性已经初始化就直接返回,没有初始化就进入同步区域,如果初始化就返回,没有初始化就执行初始化函数,保存初始化后的值并返回。
可观察的委托 Observable
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("no name") {
prop, old, new ->
println("$old -> $new")
}
}
fun main() {
val user = User()
user.name = "first"
user.name = "second"
}
运行结果如下
no name -> first
first -> second
接下来看编译后的结果
public final class User$$special$$inlined$observable$1 extends ObservableProperty {
// $FF: synthetic field
final Object $initialValue;
public User$$special$$inlined$observable$1(Object $captured_local_variable$1, Object $super_call_param$2) {
super($super_call_param$2);
this.$initialValue = $captured_local_variable$1;
}
protected void afterChange(@NotNull KProperty property, Object oldValue, Object newValue) {
Intrinsics.checkNotNullParameter(property, "property");
String var4 = (String)newValue;
String old = (String)oldValue;
int var7 = false;
String var8 = old + " -> " + var4;
boolean var9 = false;
System.out.println(var8);
}
}
public final class User {
// $FF: synthetic field
static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(User.class, "name", "getName()Ljava/lang/String;", 0))};
@NotNull
private final ReadWriteProperty name$delegate;
//转发给代理对象name$delegate
@NotNull
public final String getName() {
return (String)this.name$delegate.getValue(this, $$delegatedProperties[0]);
}
//转发给代理对象name$delegate
public final void setName(@NotNull String var1) {
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.name$delegate.setValue(this, $$delegatedProperties[0], var1);
}
public User() {
Delegates var1 = Delegates.INSTANCE;
Object initialValue$iv = "no name";
int $i$f$observable = false;
//生成代理接口的实例User$$special$$inlined$observable$1
this.name$delegate = (ReadWriteProperty)(new User$$special$$inlined$observable$1(initialValue$iv, initialValue$iv));
}
}
其中ObservableProperty的setValue会触发afterChange()方法,在这个方法中会运行观察的函数。
//官方实现的代理接口
public abstract class ObservableProperty<V>(initialValue: V) : ReadWriteProperty<Any?, V> {
private var value = initialValue
protected open fun afterChange(property: KProperty<*>, oldValue: V, newValue: V): Unit {}
public override fun getValue(thisRef: Any?, property: KProperty<*>): V {
return value
}
//setValue()会触发afterChange()回调
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
val oldValue = this.value
if (!beforeChange(property, oldValue, value)) {
return
}
this.value = value
afterChange(property, oldValue, value)
}
}
编译期间做如下几件事
- 实现ObservableProperty接口,重写afterChange方法,编写观察逻辑。
- 给代理的属性增加setXX、getXX属性。
- 生产ObservableProperty接口实现的对象,并把setXX、getXX交给ObservableProperty的setValue()、getValue();
在setValue之后会触发afterChange()方法。
这两种标准委托都是kotlin都已经编写好了中间的代理类。使用者只需要按照标准实现就可以了。