Kotlin细节十一:延迟初始化

lateinit 和by lazy

当我们不想声明一个类型可空的对象,而且也没法在构造器中初始化它,可以通过两种方式解决

  • lateinit ,告诉编译器,不要因为属性变量未被初始化而报错。这是一种压制性的做法,lateinit 不能修饰基本类型
  • lazy是一种属性委托,lazy() 是接受一个 lambda 并返回一个 Lazy < T > 实例的函数,返回的实例可以作为实现延迟属性的委托: 第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果, 后续调用 get() 只是返回记录的结果 。并且 lazy 只能用于 val 声明的不可变属性。
  • lazy 的限制,初始化时只能访问 val 属性 , 只有 val 属性可以 使用 by lazy 来延迟初始化。这也就大大增加了 使用限制。
class SimpleClass {
    val name:String by lazy{
        "zhangsan"
    }
}

lazy 实现原理

源码还是很好理解的

  • 构造器中生成代理的 Lazy实例对象
  • name 的 get 方法 返回的是 delegate.getVaule()
  • 在getVaule()第一次被调用时会将_value进行初始化,以后直接返回
  • 并通过加锁保证线程安全。
public final class SimpleClass {
   @NotNull
   private final Lazy name$delegate;

   @NotNull
   public final String getName() {
      Lazy var1 = this.name$delegate;
      Object var3 = null;
      boolean var4 = false;
      return (String)var1.getValue();
   }

   public SimpleClass() {
      this.name$delegate = LazyKt.lazy((Function0)null.INSTANCE);
   }
}
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)
}

版权声明:本文为wakewakewake原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。