一、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 <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
lazy其实就是使用默认的初始化函数initializer来创建一个lazy类型的对象,并且使用的默认的线程模型,是LazyThreadSafetyMode.SYNCHRONIZED
二、实例分析
class LazyLoadinigTest{
private val name: String by lazy{"1111"}
fun printName() {
println(name)
}
}
fun main(args: Array<String>) {
val test = LazyLoadinigTest()
test.printName()
}
将这个代码转成kotlin字节码进行分析,使用tools->kotlin->show kotlin bytecode
第一部分就是构造函数的字节码:
public <init>()V
L0
LINENUMBER 8 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()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<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, 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
网友评论