Kotlin學(xué)習(xí)筆記之屬性和方法

屬性的setter和getter方法

Kotlin中定義了一個類的屬性后,可以不用寫其settergetter方法,編譯的時候編譯器會自動為你生成。但是有時候我們需要對屬性進行一下特殊操作,這時候就需要重寫settergetter方法,那什么時候需要重寫settergetter?法。

  • 重寫setter方法時機:
    • 外部給我值時,需要做額外的處理
    • 捕獲外部給值的時機
  • 重寫getter方法時機:
    • 外部獲取值時,需要做額外的處理
    • 捕獲外部需要的時機
    • 懶加載

延遲初始化lateinit

lateinit var name: String

一個變量必須有值,但是定義時不知道給什么值,可以用lateinit修飾,后續(xù)再賦值。需要注意的是在使用前必須為其賦值。上面的代碼是延遲初始化定義name變量。

委托

委托 == 代理,我們在Java中學(xué)過一鐘設(shè)計模式為代理模式,在Kotlin中可以通過by關(guān)鍵詞讓編譯器自動生成委托代碼

interface DB{
    fun sava()
}

class SqlDB(): DB{
    override fun sava() {
        println("sava in SqlDB")
    }
}
class MySqlDB(): DB{
    override fun sava() {
        println("sava in MySqlDB")
    }
}
class OracleDB(): DB{
    override fun sava() {
        println("sava in OracleDB")
    }
}

class CreateDBAction(db: DB): DB by db

fun main(){
    CreateDBAction(SqlDB()).sava()
    CreateDBAction(MySqlDB()).sava()
    CreateDBAction(OracleDB()).sava()
}
/** 
 * sava in SqlDB
 * sava in MySqlDB
 * sava in OracleDB
 */

反編譯后編譯器將會生成完整的CreateDBAction

public final class CreateDBAction implements DB {
   // $FF: synthetic field
   private final DB $$delegate_0;

   public CreateDBAction(@NotNull DB db) {
      Intrinsics.checkNotNullParameter(db, "db");
      super();
      this.$$delegate_0 = db;
   }

   public void sava() {
      this.$$delegate_0.sava();
   }
}

懶加載委托

fun requestDownload(): String{
    println("requestDownload run ...")
    Thread.sleep(2000L) // 模擬下載延時
    return "下載成功"
}

val responseData: String by lazy { requestDownload() }

// 懶加載委托
fun main(){
    println("準備工作中")
    Thread.sleep(3000L)
    
    println("開始請求")
    println(responseData)   // 如果responseData沒有值則會執(zhí)行懶加載,否則直接打印responseData的值
    println(responseData)
    println(respomseData)
}

/**執(zhí)行結(jié)果
 * 準備工作中
 * 開始請求
 * requestDownload run ...
 * 下載成功
 * 下載成功
 * 下載成功
 */

懶加載只會調(diào)用一次,只有被調(diào)用的時候才會被加載,在上面代碼的含義為responseData變量只會被初始化一次,后面訪問的是就是變量的值。

注意:by lazy只能修飾val變量,而lateinit只能修飾var變量。

委托屬性

委托屬性公用被委托屬性的set和get方法,底層原理為編譯器生成被委托屬性的單例對象,通過該實例可以獲取到被委托對象的set和get方法,當調(diào)用委托屬性的set和get方法時就會通過該實例調(diào)用set和get方法,從而實現(xiàn)公用set和get效果。

用途:當一個應(yīng)用已經(jīng)上線,里面的一個變量名需要更改,但是又不希望對之前代碼進行修改,則可以使用屬性委托,重新定義一個變量來委托之前的屬性

class Simple{
    // version 1.0
    var info: String = "OK"
    
    // version 2.0
    var successInfo: String by ::info
}

代碼中的 var successInfo: String by ::info 這行,::info 是將 info 屬性作為委托的成員引用。這意味著 successInfo 屬性的讀取和寫入操作都會被委托給 info 屬性。successInfo 屬性的讀取操作會委托給 info 屬性的 getter 方法,而寫入操作會委托給 info 屬性的 setter 方法。通過這種方式,successInfo 屬性可以方便地訪問和操作 info 屬性的值。

自定義委托

簡單的自定義委托(依賴類)

class Owner {
    var name: String by Nicely()
}

class Nicely{
    private var str: String = "Default"
    operator fun getValue(owner: Owner, kProperty: KProperty<*>): String{
        println("get被調(diào)用了")
        return str
    }

    operator fun setValue(owner: Owner, kProperty: KProperty<*>, value: String){
        println("set被調(diào)用了")
        str = value
    }
}

fun main(){
    val owner = Owner()
    owner.name = "Nicely"
    println(owner.name)
}

/**運行結(jié)果
 * set被調(diào)用了
 * get被調(diào)用了
 * Default
 */

不依賴類(兩種方式)

// 方式一
var result: String = "Default"
private operator fun String.getValue(
    thisRef: Any?,
    property: KProperty<*>
): String {
    return result
}
private operator fun String.setValue(
    any: Any?,
    property:KProperty<*>,
    value: String
) {
    result = value
}

// 方式二
var result: String = "Default"
operator fun String.provideDelegate(
    thisRef: Any?,
    property:KProperty<*>
) = object : ReadWriteProperty<Any?, String> {
        override fun getValue(thisRef: Any?, property: KProperty<*>): String {
            println("test getValue value:$result")
            return result
        }

        override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
            println("test setValue value:$value")
            result = value
        }
    }

提供委托

在自定義委托類StringDelegator的基礎(chǔ)之上創(chuàng)建一個類SimpleDelegator實現(xiàn)動態(tài)選擇委托類,SimpleDelegator類必須實現(xiàn)provideDelegate操作符重載,方法邏輯可以自己實現(xiàn)。

kProperty為反射獲取的成員變量,根據(jù)反射獲得的成員變量名的不同來調(diào)用不同的自定義委托對象。

注意:在方法中定義的變量無法進行屬性委托,因為無法通過反射獲取該臨時變量。

class StringDelegator(private var str: String): ReadWriteProperty<Owner2, String>{
    override fun getValue(thisRef: Owner2, property: KProperty<*>): String {
        println("StringDelegator#getValue run...")
        return str
    }

    override fun setValue(thisRef: Owner2, property: KProperty<*>, value: String) {
        println("StringDelegator#setValue run...")
        str = value
    }
}

class SimpleDelegator {
    operator fun provideDelegate(
        owner2: Owner2,
        kProperty: KProperty<*>
    ): ReadWriteProperty<Owner2, String>{
        return if (kProperty.name.contains("name")){
            StringDelegator("Nicely")
        }else{
            StringDelegator("ChongQing")
        }
    }

}

class Owner2{
    var name: String by SimpleDelegator()
    var address: String by SimpleDelegator()
}

fun main(){
    val owner = Owner2()
    owner.name = "Tom"
    owner.address = "BeiBei"
    println(owner.name)
    println(owner.address)
}

/**執(zhí)行結(jié)果
 * StringDelegator#setValue run...
 * StringDelegator#setValue run...
 * StringDelegator#getValue run...
 * Tom
 * StringDelegator#getValue run...
 * BeiBei
 */

用途

用途一:觀察 新值 舊值

class Simple1 {
    var name: String by Delegates.observable("Test") {
            prop, old, new ->
        println("舊值:$old -> 新值:$new")
    }
}

fun main() {
    val simple1 = Simple1()
    simple1.name = "Update1"
    simple1.name = "Update2"
}
/** Output:
 * 舊值:Test -> 新值:Update1
 * 舊值:Update1 -> 新值:Update2
 */

用途二:觀察 setValue 與 getValue

class Item {
    var info: String by object : ReadWriteProperty<Item, String> {
        override fun getValue(thisRef: Item, property: KProperty<*>): String {
            println("監(jiān)聽到,你在獲取值")
            return ""
        }

        override fun setValue(thisRef: Item, property: KProperty<*>, value: String) {
            println("監(jiān)聽到,你在設(shè)置值 value:$value")
        }
    }
}

fun main() {
    val item = Item()
    item.info = "Derry"
    println(item.info)
}
/** Output:
 * 監(jiān)聽到,你在設(shè)置值 value:Derry
 * 監(jiān)聽到,你在獲取值
 */
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容