<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                Kotlin標準庫中,已經自定義了一系列標準委托,包括了大部分有用的委托。 可參考本文前面的系列文章——[委托屬性](http://www.hmoore.net/alex_wsc/android_kotlin/1318315) [TOC] ## 延遲加載(Lazy) 在Kotlin中,聲明變量或者屬性的同時要對其進行初始化,否則就會報異常,**盡管我們可以定義可空類型的變量,但有時卻不想這樣做,能不能在變量使用時再進行初始化呢**?為此,Kotlin中提供了延遲加載(又稱懶加載)功能,當變量被訪問時才會被初始化,這樣不僅可以提高程序效率,還可以讓程序啟動更快。 延遲加載是通過“by lazy”關鍵字標識的,延遲加載的變量要求聲明為val,即不可變變量,相當于Java中用final關鍵字修飾的變量。 **延遲加載也是委托的一種形式**,延遲加載的語法結構如下: ``` val/var變量:變量類型by lazy{ 變量初始化代碼 } ``` >[info]需要注意的是,延遲加載的變量在第1次初始化時會輸出代碼塊中的所有內容,之后在調用該變量時,都只會輸出最后一行代碼的內容。 ### 定義 lazy()是一個函數,接受一個Lambda表達式作為參數,返回一個Lazy類型的實例,這個實例可以作為一個委托,,實現延遲加載屬性(lazy property):第一次調用 get() 時,將會執行 lazy() 函數受到的Lambda 表達式,然后會記住這次執行的結果,以后所有對 get() 的調用都只會簡單地返回以前記住的結果。 ### 語法結構 ``` val/var 變量: 變量類型 by lazy{ 變量初始化代碼 } ``` ### 案例分析 針對延遲加載lazy,我們需要知道兩個結論。 1. 延遲屬性只有在訪問的時候才會被初始化。 2. 延遲屬性只會初始化一次。 參考代碼: ![](http://upload-images.jianshu.io/upload_images/7368752-8b9db857d0064590.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 針對以上代碼,我們在7行打個斷點,然后debug運行程序。可以看到【normalValue】已經賦值成功,而【lazyValue】則提示“Lazy value not initialized yet.”。 參考截圖: ![](http://upload-images.jianshu.io/upload_images/7368752-d8a43e00da6d7733.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 之所以出現現在的情況,因為我們還沒有訪問到【lazyValue】,我們接著執行完第17行,將會看到lazyValue被初始化了。 參考截圖: ![](http://upload-images.jianshu.io/upload_images/7368752-62eebf6720a9b6bb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 我們接著執行完所有代碼,看結果輸出: ![](http://upload-images.jianshu.io/upload_images/7368752-e34a245acea82988.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 可以看到【println("lazyValue進行初始化")】只被輸出了一次。所以,延遲屬性lazy只初始化一次。 ## 可觀察屬性(Observable) ### 定義 Delegates.observable()函數接受兩個參數: 第一個是初始化值,第二個是屬性值變化事件的響應器(handler)。這種形式的委托,采用了觀察者模式,其會檢測可觀察屬性的變化,當被觀察屬性的setter()方法被調用的時候,響應器(handler)都會被調用(在屬性賦值處理完成之后)并自動執行執行的lambda表達式,同時響應器會收到三個參數:被賦值的屬性, 賦值前的舊屬性值, 以及賦值后的新屬性值。 ### 語法結構 ![](http://upload-images.jianshu.io/upload_images/7368752-d5c94e770f98a30c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 其中Lambda表達式(變化事件的響應器)會在變量的setter()被調用的時候觸發。 Lambda里面可以獲取三個參數: * prop-被賦值的屬性; * old-賦值前的舊屬性值; * new-賦值后的新屬性值; ### 案例分析 參考代碼: ![](http://upload-images.jianshu.io/upload_images/7368752-b1e2406f489547dd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 針對以上代碼,第13行和第16行代碼對屬性進行了修改,所以我們的屬性變化事件響應器被觸發了2次。 ## Vetoable ### 定義 Delegates.vetoable()函數接受兩個參數:第一個是初始化值,第二個是屬性值變化事件的響應器(handler),是可觀察屬性(Observable)的一個特例,不同的是在響應器指定的自動執行執行的lambda表達式中在保存新值之前做一些條件判斷,來決定是否將新值保存。 ### 語法結構 ![](http://upload-images.jianshu.io/upload_images/7368752-f92ba244db06b95e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) * Lambda 返回true:變量會被修改 * Lambda返回false:變量不會被修改 ### 案例分析 參考代碼: ![](http://upload-images.jianshu.io/upload_images/7368752-f51bbf5edb2beef5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 結果分析: 針對以上代碼,代碼在第15行和第19行,對userName進行了修改,每次修改都觸發了Lambda表達式的執行。但是第15行新的屬性值【"heima"】不滿足【new.contains("黑馬")】,所以沒有賦值,所以16行輸出結果是【userName當前屬性值:黑馬程序員】。 ## notNull ### 定義 **對于一個不可為“non-null”的變量,我們需要保證它被正確的賦值。賦值操作可以在變量定義的時候,也可以后續代碼里面進行賦值。我們只需要在變量后面使用notNull屬性委托,編譯器就允許我們后續進行賦值**。 加了notNull的屬性委托,編譯器允許我們后續賦值,那我們也有可能忘記賦值,這樣使用變量的時候就會報空指針。那有的同學可能會說,我已經養成了良好的習慣,在使用變量之前會進行非空判斷,這樣的做法會導致有大量的非空判斷,這是不美觀的。其實這個時候即使做非空判斷也會拋出異常(UninitializedPropertyAccessException)。因為notNull的屬性委托,要求變量被引用的時候被賦值。 ### 語法結構 ![](http://upload-images.jianshu.io/upload_images/7368752-939ee15010ba44c8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ### 案例分析 參考代碼: ![](http://upload-images.jianshu.io/upload_images/7368752-be4fe4483a2fa780.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 結果分析: 針對以上代碼的第11行,因為我們使用了notNull的屬性委托,所以編譯器允許【userName】后續進行賦值。 針對以上代碼的第16行對【user.userName】進行非空判斷,然后在第17行進行使用,感覺上不會有什么問題,但是結果大家看到了,報了空指針異常。說明,**我們用了notNull屬性委托之后,在第16行的時候用到了【user.userName】,這個時候如果我們沒有賦值就會拋出異常,提示“lateinit propety userName has not been initialized”**。 ## 將多個屬性保存在一個map內 ### 定義 Kotlin的map委托,提供了map和對象一一綁定關系,就是map的值可以決定對象的值,修改map的值也可以影響對象的值。但是這一切需要滿足,map的key和屬性的名稱保證一致。 ### 語法結構 ``` val/var 變量: 變量類型by 實現Map接口的對象 ``` ### 案例分析 參考代碼: ![](http://upload-images.jianshu.io/upload_images/7368752-248bd08d365e7d3a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 提示: 針對以上代碼的第7行用到的【MutableMap】,也可以改為其他map,但是如果要想修改map集合里面的值,必須使用MutableMap接口對象。 ? ?
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看