kotlin-by lazy实现原理

一、lazy的定义

lazy是一个定义在LazyJVM中的函数,有两种实现。这里看其中一种:

/**
 * Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
 * and the default thread-safety mode [LazyThreadSafetyMode.SYNCHRONIZED].
 *
 * If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access.
 *
 * Note that the returned instance uses itself to synchronize on. Do not synchronize from external code on
 * the returned instance as it may cause accidental deadlock. Also this behavior can be changed in the future.
 */
public actual fun  lazy(initializer: () -> T): Lazy = SynchronizedLazyImpl(initializer)

lazy其实就是使用默认的初始化函数initializer来创建一个lazy类型的对象,并且使用的默认的线程模型,是LazyThreadSafetyMode.SYNCHRONIZED

二、实例分析

class LazyLoadinigTest{

    private val name: String by lazy{"1111"}

    fun printName() {
        println(name)
    }
}

fun main(args: Array) {
    val test = LazyLoadinigTest()
    test.printName()
}

将这个代码转成kotlin字节码进行分析,使用tools->kotlin->show kotlin bytecode
第一部分就是构造函数的字节码:

  public ()V
   L0
    LINENUMBER 8 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object. ()V
   L1
    LINENUMBER 10 L1
    ALOAD 0
    GETSTATIC com/nene/kttest/LazyLoadinigTest$name$2.INSTANCE : Lcom/nene/kttest/LazyLoadinigTest$name$2;
    CHECKCAST kotlin/jvm/functions/Function0
    INVOKESTATIC kotlin/LazyKt.lazy (Lkotlin/jvm/functions/Function0;)Lkotlin/Lazy;
    PUTFIELD com/nene/kttest/LazyLoadinigTest.name$delegate : Lkotlin/Lazy;
    RETURN
   L2
    LOCALVARIABLE this Lcom/nene/kttest/LazyLoadinigTest; L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1

从这里可以看出,编译成字节码之后,构造器中并没有定义一个name属性,而是定义了一个name2.INSTANCE,然后检查是否可以转成Function0类型,并且将这个静态变量作为属性值传入LazyKt.lazy函数中,获取到返回值,接着将这个返回值赋值给了namedelegate=LazyKt.lazy((Function0)name2是一个编译生成的内部类
从这里可以看出,name$2.INSTANCE其实就是()->T的一种具体实现
而延迟加载,其实就是在使用的时候才加载数据,所以name属性需要看其getter函数,即getName()。

  private final getName()Ljava/lang/String;
   L0
    ALOAD 0
    GETFIELD com/nene/kttest/LazyLoadinigTest.name$delegate : Lkotlin/Lazy;
    ASTORE 1
    ALOAD 0
    ASTORE 2
    GETSTATIC com/nene/kttest/LazyLoadinigTest.$$delegatedProperties : [Lkotlin/reflect/KProperty;
    ICONST_0
    AALOAD
    ASTORE 3
   L1
    ALOAD 1
    INVOKEINTERFACE kotlin/Lazy.getValue ()Ljava/lang/Object;
   L2
    CHECKCAST java/lang/String
    ARETURN
   L3
    LOCALVARIABLE this Lcom/nene/kttest/LazyLoadinigTest; L0 L3 0
    MAXSTACK = 2
    MAXLOCALS = 4

这段字节码转成java伪代码,其实可以变成:

private final int getName(){
    Lazy var1 = this.name$delegate;
    KProperty var2 = this.$$delegatedProperties[0]
    return ((Number)var1.getValue()).intValue()
}

从这里可以看出,name的getter函数最终是返回了namedelegate,又是由LazyKt.lazy()获取到的返回值,所以看LazyKt.lazy函数,而这个函数其实就是LazyJVM.lazy()
所以其函数返回值就是SynchronizedLazyImpl对象

三、SynchronizedLazyImpl

// 继承Lazy并且实现了Serializable接口
// 数据返回其实就是返回的SynchronizedLazyImpl.getValue()
private class SynchronizedLazyImpl(initializer: () -> T, lock: Any? = null) : Lazy, Serializable {
    // 定义一个() -> T高阶函数类型的变量并且赋初始值initializer
    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
    // 重写了value属性
    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 {
                    // 调用传入的lambda表达式进行初始化
                    // 并且保存结果,然后返回
                    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源码中,是继承自Lazy;并且其内部定义了一个volatile修饰的_value属性,这样做的目的是当一个线程修改属性值的时候,其他线程可以得到最新的值。
而SynchronizedLazyImpl的getValue()函数,其实就是重写其value的get(),在这里就是做判断,判断_value是否已经初始化,不管是被当前线程还是其他线程,如果已经初始化,则直接返回,如果没有被初始化,则调用传入的lambda表达式进行初始化,得到lambda表达式的返回值进行赋值,然后再将lambda表达式类型对象置为null

你可能感兴趣的:(kotlin-by lazy实现原理)