Kotlin for android學(xué)習(xí)三:擴(kuò)展函數(shù)與擴(kuò)展屬性

前言

kotlin官網(wǎng) (中文版)和kotlin教程學(xué)習(xí)教程的筆記场躯。

一、擴(kuò)展函數(shù)

  1. 直接舉個(gè)例子吧
fun <T> MutableList<T>.swap(index1: Int, index2: Int) { 
  val tmp = this[index1] // this關(guān)鍵字指代接收者對象旅挤,這里指代list實(shí)例,
  this[index1] = this[index2]
  this[index2] = tmp
}

  var list = mutableListOf(1, 2, 3)
  list.swap(0, 2)//對任意一個(gè) MutableList<T> 對象調(diào)用這個(gè)擴(kuò)展函數(shù)
  println(list.toString()) //輸出結(jié)果為[3, 2, 1]
  1. 擴(kuò)展函數(shù)是靜態(tài)解析的L吖亍!粘茄!
    擴(kuò)展函數(shù)是靜態(tài)解析的G┪琛!柒瓣!
    擴(kuò)展函數(shù)是靜態(tài)解析的H宕睢!芙贫!
    重要的話說三遍搂鲫,意思如下:

調(diào)用擴(kuò)展函數(shù)時(shí), 具體被調(diào)用的函數(shù)是哪一個(gè), 是通過調(diào)用函數(shù)的對象表達(dá)式的類型來決定的, 而不是 在運(yùn)行時(shí)刻表達(dá)式動(dòng)態(tài)計(jì)算的最終結(jié)果類型決定的

不太清晰,請看下例:

open class C
class D: C()
fun C.foo() = "c"
fun D.foo() = "d"
fun printFoo(c: C) {
  println(c.foo()) 
}
printFoo(D()) //輸出c

那么磺平,如果類中存在成員函數(shù), 同時(shí)又在同一個(gè)類上定義了同名同參數(shù)的擴(kuò)展函數(shù)會怎樣魂仍?這種情況下總是會優(yōu)先使用成員函數(shù)

class C {
fun foo() { println("member") }
}
fun C.foo() { println("extension") }

c.foo() // 輸出member
  1. 將擴(kuò)展定義為成員,看下例:
 class C
    class D {
        fun C.foo() {
            println(toString())
            println(this@D.toString())
        }
        fun call(c: C) {
            c.foo()
        }
    }
        D().call(C())

輸出結(jié)果如下:



這里,我們可以看到拣挪,默認(rèn)調(diào)用了擴(kuò)展方法定義的類的方法蓄诽。

引入一個(gè)概念:

  1. 在類的內(nèi)部, 你可以為另一個(gè)類定義擴(kuò)展. 在這類擴(kuò)展中, 存在多個(gè) 隱含接受者(implicit receiver) - 這些隱 含接收者的成員可以不使用限定符直接訪問.
  2. 擴(kuò)展方法的定義所在的類的實(shí)例, 稱為_派發(fā)接受者(dispatch receiver),
    擴(kuò)展方法的目標(biāo)類型的實(shí)例, 稱為 _擴(kuò)展接受者(extension receiver) .
  3. 當(dāng)派發(fā)接受者與擴(kuò)展接受者的成員名稱發(fā)生沖突時(shí), 擴(kuò)展接受者的成員將會被優(yōu)先使用.

這個(gè)例子中,C為擴(kuò)展接受者媒吗,D為派發(fā)接受者。

  1. 小試牛刀
open class D
    class D1 : D()
    open class C {
        open fun D.foo() {
            println("D.foo in C")
        }

        open fun D1.foo() {
            println("D1.foo in C")
        }

        fun caller(d: D) {
            d.foo() // 調(diào)用擴(kuò)展函數(shù)
        }
    }

    class C1 : C() {
        override fun D.foo() {
            println("D.foo in C1")
        }

        override fun D1.foo() {
            println("D1.foo in C1")
        }
    }
//-----看好題了么乙埃?-測試開始---
     C().caller(D())  //輸出闸英?锯岖?
     C1().caller(D())  //輸出?甫何?
     C().caller(D1()) //輸出出吹??

答案揭曉:

C().caller(D()) // 打印結(jié)果為 "D.foo in C"
C1().caller(D()) // 打印結(jié)果為 "D.foo in C1" - 派發(fā)接受者的解析過程是虛擬的 
C().caller(D1()) // 打印結(jié)果為 "D.foo in C" - 擴(kuò)展接受者的解析過程是靜態(tài)的

你答對了么辙喂?

二捶牢、擴(kuò)展屬性

 val String.upper
        get() = toUpperCase()

   var s = "aBcDefg"
        println(s.upper)//輸出ABCDEFG

擴(kuò)展屬性不應(yīng)該初始化,因?yàn)閿U(kuò)展屬性沒有后端域變量巍耗,在上一節(jié)中我們說“初始化給定的值將直接寫入后端域變量中”秋麸,因此不能夠初始化。
那么為何沒有后端域變量呢炬太?由于擴(kuò)展屬性實(shí)際上不會向類添加新的成員, 因此無法讓一個(gè)擴(kuò)展屬性擁有一個(gè) 后端域變量

三灸蟆、對同伴對象(Companion Object)的擴(kuò)展

什么是同伴對象?由于Kotlin 的類沒有靜態(tài)方法, 大多數(shù)情況下, 建議使用包級函數(shù)替代, 或者使用同伴對象,達(dá)到靜態(tài)方法效果

package com.example.demo
 class User { 
   companion object { //同伴對象
        fun foo(){  }
   }
}
fun pfoo(){} //包級函數(shù)

User.foo() //這樣亲族,調(diào)用的時(shí)候就不需要使用對象調(diào)用了
  pfoo()

對這個(gè)同伴對象定義擴(kuò)展函數(shù)和擴(kuò)展屬性:

class User {
    companion object { //同伴對象
        fun foo() {}
    }
}
fun pfoo() {} //包級函數(shù)

fun User.Companion.cfoo() {} // 對這個(gè)同伴對象定義擴(kuò)展函數(shù)
val User.Companion.getData: String // 對這個(gè)同伴對象定義擴(kuò)展屬性
    get() = toString()

User.foo()
pfoo()
User.cfoo()//與同伴對象的常規(guī)成員一樣, 可以只使用類名限定符來調(diào)用這些擴(kuò)展函數(shù)和擴(kuò)展屬性
println(User.getData) //輸出com.example.demo.User$Companion@9bdf2f3

四炒考、使用擴(kuò)展的動(dòng)機(jī)

擴(kuò)展函數(shù)數(shù)是指在一個(gè)類上增加一種新的行為,甚至我們沒有這個(gè)類代碼的訪問權(quán)限霎迫。這是一個(gè)在缺少有用函數(shù)的類上擴(kuò)展的方法斋枢。在Java中,通常會實(shí)現(xiàn)很多帶有 static方法的工具類知给。Kotlin中擴(kuò)展函數(shù)的一個(gè)優(yōu)勢是我們不需要在調(diào)用方法的時(shí)候 把整個(gè)對象當(dāng)作參數(shù)傳入
總而言之就是瓤帚,解決**Utils.的麻煩,解決靜態(tài)導(dǎo)入無法使用代碼補(bǔ)全功能的麻煩

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末炼鞠,一起剝皮案震驚了整個(gè)濱河市缘滥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谒主,老刑警劉巖朝扼,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異霎肯,居然都是意外死亡擎颖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進(jìn)店門观游,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搂捧,“玉大人,你說我怎么就攤上這事懂缕≡逝埽” “怎么了?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長聋丝。 經(jīng)常有香客問我索烹,道長,這世上最難降的妖魔是什么弱睦? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任百姓,我火速辦了婚禮,結(jié)果婚禮上况木,老公的妹妹穿的比我還像新娘垒拢。我一直安慰自己,他們只是感情好火惊,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布求类。 她就那樣靜靜地躺著,像睡著了一般矗晃。 火紅的嫁衣襯著肌膚如雪仑嗅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天张症,我揣著相機(jī)與錄音仓技,去河邊找鬼。 笑死俗他,一個(gè)胖子當(dāng)著我的面吹牛脖捻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播兆衅,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼地沮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了羡亩?” 一聲冷哼從身側(cè)響起摩疑,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎畏铆,沒想到半個(gè)月后雷袋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辞居,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年楷怒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓦灶。...
    茶點(diǎn)故事閱讀 40,872評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鸠删,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贼陶,到底是詐尸還是另有隱情刃泡,我是刑警寧澤巧娱,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站捅僵,受9級特大地震影響家卖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜庙楚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望趴樱。 院中可真熱鬧馒闷,春花似錦、人聲如沸叁征。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捺疼。三九已至疏虫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間啤呼,已是汗流浹背卧秘。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留官扣,地道東北人翅敌。 一個(gè)月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像惕蹄,于是被迫代替她去往敵國和親蚯涮。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評論 2 361

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