两分钟学习--标准委托

255 阅读4分钟

图像 171.png

延迟属性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都已经编写好了中间的代理类。使用者只需要按照标准实现就可以了。