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

屬性的setter和getter方法

Kotlin中定義了一個類的屬性后继准,可以不用寫其settergetter方法,編譯的時候編譯器會自動為你生成归敬。但是有時候我們需要對屬性進(jìn)行一下特殊操作惨寿,這時候就需要重寫settergetter方法香璃,那什么時候需要重寫settergetter?法噩咪。

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

延遲初始化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("準(zhǔn)備工作中")
    Thread.sleep(3000L)
    
    println("開始請求")
    println(responseData)   // 如果responseData沒有值則會執(zhí)行懶加載髓迎,否則直接打印responseData的值
    println(responseData)
    println(respomseData)
}

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

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

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

委托屬性

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

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

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)用不同的自定義委托對象。

注意:在方法中定義的變量無法進(jìn)行屬性委托暂吉,因為無法通過反射獲取該臨時變量胖秒。

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)系作者
  • 序言:七十年代末肮街,一起剝皮案震驚了整個濱河市风题,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嫉父,老刑警劉巖沛硅,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異绕辖,居然都是意外死亡摇肌,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門仪际,熙熙樓的掌柜王于貴愁眉苦臉地迎上來围小,“玉大人昵骤,你說我怎么就攤上這事》宰ィ” “怎么了涉茧?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長疹娶。 經(jīng)常有香客問我伴栓,道長,這世上最難降的妖魔是什么雨饺? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任钳垮,我火速辦了婚禮,結(jié)果婚禮上额港,老公的妹妹穿的比我還像新娘饺窿。我一直安慰自己,他們只是感情好移斩,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布肚医。 她就那樣靜靜地躺著,像睡著了一般向瓷。 火紅的嫁衣襯著肌膚如雪肠套。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天猖任,我揣著相機(jī)與錄音你稚,去河邊找鬼。 笑死朱躺,一個胖子當(dāng)著我的面吹牛刁赖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播长搀,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼宇弛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了源请?” 一聲冷哼從身側(cè)響起涯肩,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎巢钓,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疗垛,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡症汹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了贷腕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片背镇。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡咬展,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瞒斩,到底是詐尸還是另有隱情破婆,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布胸囱,位于F島的核電站祷舀,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏烹笔。R本人自食惡果不足惜裳扯,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谤职。 院中可真熱鬧饰豺,春花似錦、人聲如沸允蜈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饶套。三九已至漩蟆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間凤跑,已是汗流浹背爆安。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留仔引,地道東北人扔仓。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像咖耘,于是被迫代替她去往敵國和親翘簇。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容