中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Kotlin對象的懶加載方式by?lazy與lateinit異同點是什么

發布時間:2022-10-12 10:24:16 來源:億速云 閱讀:125 作者:iii 欄目:開發技術

這篇文章主要講解了“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
        }
    }
    • notNull方法我們可以看到就是說這個對象不能為null,否則就會拋出異常。

    • observable方法主要用于監控屬性值發生變更,類似于一個觀察者。當屬性值被修改后會往外部拋出一個變更的回調。

    • vetoable方法跟observable類似,都是用于監控屬性值發生變更,當屬性值被修改后會往外部拋出一個變更的回調。與observable不同的是這個回調會返回一個Boolean值,來決定此次屬性值是否執行修改。

    其實用不用委托沒什么區別,就是看是否需要屬性變化的回調監聽,否則我們直接用變量即可

       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() 返回的是一個存儲在lambda初始化器中的Lazy類型實例。

    • getter的第一次調用執行傳遞給lazy()的lambda并存儲其結果。

    • 后面再調用的話,getter調用只返回存儲中的值。

    簡單地說,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)

    我們需要考慮的是線程安全和非線程安全

    • SYNCHRONIZED通過加鎖來確保只有一個線程可以初始化Lazy實例,是線程安全的

    • PUBLICATION表示不加鎖,可以并發訪問多次調用,但是我之接收第一個返回的值作為Lazy的實例,其他后面返回的是啥玩意兒我不管。這也是線程安全的

    • NONE不加鎖,是線程不安全的

    感謝各位的閱讀,以上就是“Kotlin對象的懶加載方式by lazy與lateinit異同點是什么”的內容了,經過本文的學習后,相信大家對Kotlin對象的懶加載方式by lazy與lateinit異同點是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    泗洪县| 溆浦县| 肥西县| 开阳县| 紫金县| 全椒县| 西充县| 绍兴市| 岳阳市| 墨竹工卡县| 山西省| 博白县| 宣汉县| 景谷| 卓资县| 商水县| 延川县| 西藏| 石家庄市| 明光市| 瑞安市| 滦平县| 明溪县| 穆棱市| 分宜县| 鄂托克前旗| 东辽县| 杂多县| 江油市| 黄冈市| 哈密市| 龙岩市| 儋州市| 宜兰县| 湘潭县| 外汇| 忻城县| 洪洞县| 紫金县| 东丽区| 绍兴县|