Kotlin-委托剖析(3)- by lazy

2022-04-01  本文已影响0人  杨0612
使用场景

希望b对象只构建一次,那么就可以用到by lazy 委托。

class MyApplication : Application() {
    val b by lazy { B() }
}

那么它是如何保证对象只构建一次呢?先看下源码

by关键字源码
@kotlin.internal.InlineOnly
public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value

这个是Lazy<T>的扩展函数,operator关键字表明:by是运算符重载。访问b对象,就是调用Lazy<T>对象的getValue函数,而函数返回Lazy<T>对象的value值。

lazy关键字源码
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)

返回一个SynchronizedLazyImpl对象,包含lambda表达式,也就是上述示例代码中的 { B() }

初步判断:外部访问b对象,也就是触发SynchronizedLazyImpl的getValue函数;

//伪代码
class MyApplication : Application() {
    val b = SynchronizedLazyImpl().getValue()
}
再反编译看看
public final class MyApplication extends Application {
   @NotNull
   private final Lazy b$delegate;//1

   @NotNull
   public final B getB() {//2
      Lazy var1 = this.b$delegate;
      Object var3 = null;
      boolean var4 = false;
      return (B)var1.getValue();
   }

   public MyApplication() {
      this.b$delegate = LazyKt.lazy((Function0)null.INSTANCE);//3
   }
}
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {//1
    private var initializer: (() -> T)? = initializer
    @Volatile private var _value: Any? = UNINITIALIZED_VALUE
    private val lock = lock ?: this

    override val value: T
        get() {//2
            val _v1 = _value
            if (_v1 !== UNINITIALIZED_VALUE) {//3
                @Suppress("UNCHECKED_CAST")
                return _v1 as T
            }

            return synchronized(lock) {//4
                val _v2 = _value
                if (_v2 !== UNINITIALIZED_VALUE) {//5
                    @Suppress("UNCHECKED_CAST") (_v2 as T)
                } else {
                    val typedValue = initializer!!()//6
                    _value = typedValue
                    initializer = null
                    typedValue//7
                }
            }
        }
......
}
总结

by lazy 具体实现转移给SynchronizedLazyImpl进行处理,其保证了lamdbda只执行一次,而且是线程安全的。

以上分析有不对的地方,请指出,互相学习,谢谢哦!

上一篇下一篇

猜你喜欢

热点阅读