Kotlin对象的懒加载方式by lazy与lateinit异同点是什么

发布时间:2022-10-12 10:24:16 作者:iii
来源:亿速云 阅读:114

这篇文章主要讲解了“Kotlin对象的懒加载方式by lazy与lateinit异同点是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Kotlin对象的懒加载方式by lazy与lateinit异同点是什么”吧!

前言

属性或对象的延时加载是我们相当常用的,一般我们都是使用 lateinit 和 by lazy 来实现。

他们两者都是延时初始化,那么在使用时那么他们两者有什么区别呢?

lateinit

见名知意,延时初始化的标记。lateinit var可以让我们声明一个变量并且不用马上初始化,在我们需要的时候进行手动初始化即可。

如果我们不初始化会怎样?

    private lateinit var name: String
    findViewById<Button>(R.id.btn_load).click {
        YYLogUtils.w("name:$name age:$age")
    }

会报错:

Kotlin对象的懒加载方式by lazy与lateinit异同点是什么

所以对应这一种情况我们会有一个是否初始化的判断

    private lateinit var name: String
    findViewById<Button>(R.id.btn_load).click {
        if (this::name.isInitialized) {
           YYLogUtils.w("name:$name age:$age")
        }   
    }

lateinit var的作用相对较简单,其实就是让编译期在检查时不要因为属性变量未被初始化而报错。(注意一定要记得初始化哦!)

by lazy

by lazy 委托延时处理,分为委托和延时

其实如果我们不想延时初始化,我们直接使用委托by也可以实现。

   private var age: Int by Delegates.observable(18) { property, oldValue, newValue ->
        YYLogUtils.w("发生了回调 property:$property oldValue:$oldValue newValue:$newValue")
    }
    findViewById<Button>(R.id.btn_load).click {
        age = 25
        YYLogUtils.w("name:$name age:$age")
    }

我们通过 by Delegates 的方式就可以指定委托对象,这里我用的 Delegates.obsevable 它的作用是修改 age 的值之后会有回调的处理。

运行的效果:

Kotlin对象的懒加载方式by lazy与lateinit异同点是什么

除了 Delegates.obsevable 它还有其他的用法。

public object Delegates {
    public fun <T : Any> notNull(): ReadWriteProperty<Any?, T> = NotNullVar()
    public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
            ReadWriteProperty<Any?, T> =
        object : ObservableProperty<T>(initialValue) {
            override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
        }
    public inline fun <T> vetoable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean):
            ReadWriteProperty<Any?, T> =
        object : ObservableProperty<T>(initialValue) {
            override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = onChange(property, oldValue, newValue)
        }
}
private class NotNullVar<T : Any>() : ReadWriteProperty<Any?, T> {
    private var value: T? = null
    public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
    }
    public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}

其实用不用委托没什么区别,就是看是否需要属性变化的回调监听,否则我们直接用变量即可

   private var age: Int  = 18
    findViewById<Button>(R.id.btn_load).click {
        age = 25
        YYLogUtils.w("name:$name age:$age")
    }

如果我们想实现延时初始化的关键就是 lazy 关键字,所以,lazy是如何工作的呢? 让我们一起在Kotlin标准库参考中总结lazy()方法,如下所示:

Kotlin对象的懒加载方式by lazy与lateinit异同点是什么

简单地说,lazy创建一个实例,在第一次访问属性值时执行初始化,存储结果并返回存储的值。

   private val age: Int by lazy { 18 / 2 }
    findViewById<Button>(R.id.btn_load).click {
        age = 25
        YYLogUtils.w("name:$name age:$age")
    }

由于我们使用的是 by lazy ,归根到底还是一种委托,只是它是一种特殊的委托,它的过程是这样的:

我们的属性 age 需要 by lazy 时,它生成一个该属性的附加属性:age?delegate。 在构造器中,将使用 lazy(()->T) 创建的 Lazy 实例对象赋值给 age?delegate。 当该属性被调用,即其getter方法被调用时返回 age?delegate.getVaule(),而 age?delegate.getVaule()方法的返回结果是对象 age?delegate 内部的 _value 属性值,在getVaule()第一次被调用时会将_value进行初始化并储存起来,往后都是直接将_value的值返回,从而实现属性值的唯一一次的初始化,并无法再次修改。所以它是只读的。

当我们调用这个 age 这个属性的时候才会初始化,它属于一种懒加载,既然是懒加载,就必然涉及到线程安全的问题,我们看看lazy是怎么解决的。

public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
public actual fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
    when (mode) {
        LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer)
        LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer)
        LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
    }
public actual fun <T> lazy(lock: Any?, initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer, lock)

我们需要考虑的是线程安全和非线程安全

感谢各位的阅读,以上就是“Kotlin对象的懒加载方式by lazy与lateinit异同点是什么”的内容了,经过本文的学习后,相信大家对Kotlin对象的懒加载方式by lazy与lateinit异同点是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

推荐阅读:
  1. 20.Swift懒加载lazy
  2. Kotlin使用技巧之lateinit修饰符

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

kotlin lateinit

上一篇:Vue enter回车导致页面刷新问题如何解决

下一篇:Redis BloomFilter布隆过滤器如何实现

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》