從零開始學Kotlin-擴展函數(10)

從零開始學Kotlin基礎篇系列文章

什麼是擴展函數

  • 擴展函數數是指在一個類上增長一種新的行爲,咱們甚至沒有這個類代碼的訪問權限;
  • Kotlin 能夠對一個類的屬性和方法進行擴展,且不須要繼承或使用 Decorator 模式;
  • 擴展是一種靜態行爲,對被擴展的類代碼自己不會形成任何影響。

擴展函數

  • 擴展函數能夠在已有類中添加新的方法,不會對原類作修改;
//擴展函數定義形式:
    fun receiverType.functionName(params){
        body
    }
  • receiverType:表示函數的接收者,也就是函數擴展的對象
  • functionName:擴展函數的名稱
  • params:擴展函數的參數,能夠爲NULL
class ClassDemo {
        fun ClassDemo.showMsg(name: String) {//擴展函數
            print(name)
        }
    }
    fun MutableList<Int>.swap(index: Int, index1: Int) {//擴展系統函數,調換位置
        //his關鍵字指代接收者對象(receiver object),
        val tmp = this[index]
        this[index] = this[index1]
        this[index1] = tmp
    }
  • 擴展函數是靜態解析的,並非接收者類型的虛擬成員,在調用擴展函數時,具體被調用的的是哪個函數,由調用函數的的對象表達式來決定的,而不是動態的類型決定的:;
open class Person
    class Student : Person()

    fun Person.getInfo() ="Person Info"//擴展Person類方法
    fun Student.getInfo() ="Student Info"//擴展Student類方法

    fun printMsg(person: Person) {
        print(person.getInfo())//此處指定爲Person類型
    }

    fun main() {
        printMsg(Student())//輸出結果:Person Info
    }
  • 若擴展函數和成員函數一致,則使用該函數時,會優先使用成員函數;
class Teacher {
        fun doWork() {
            print("成員函數")
        }
    }

    fun Teacher.doWork() {
        print("擴展函數")
    }

    fun showDoWork() {
        val teacher = Teacher()
        teacher.doWork()//輸出結果:成員函數
    }

擴展一個空對象

  • 在擴展函數內, 能夠經過 this 來判斷接收者是否爲 NULL,這樣,即便接收者爲 NULL,也能夠調用擴展函數
fun Teacher?.printMsf(): String {
        if (this == null) return "null"
        return "我是Teacher"
    }

    fun main() {
        val teacher = null
        print(teacher.printMsf())//輸出結果爲:null
        val rTeacher = Teacher()
        print(rTeacher.printMsf())//輸出結果:我是Teacher
    }

擴展屬性

  • 擴展屬性容許定義在類或者kotlin文件中,不容許定義在函數中。初始化屬性由於屬性沒有後端字段(backing field),因此不容許被初始化,只能由顯式提供的 getter/setter 定義;
val <T> List<T>.lastIndex: Int//擴展一個獲取List最後一個索引的方法
        get() = size - 1

伴生對象的擴展

  • 若是一個類定義有一個伴生對象,也能夠爲伴生對象定義擴展函數和屬性;伴生對象經過"類名."形式調用伴生對象,伴生對象聲明的擴展函數,經過用類名限定符來調用:
class ClassDemo {
        companion object {
        }

        fun ClassDemo.Companion.showMsg() {
            print("伴生對象的擴展函數")
        }

        val ClassDemo.Companion.name: String
            get() = "伴生對象的擴展屬性"
    }

做用域

  • 一般擴展函數或屬性定義在頂級包下
//一、在包名.demop10下建立一個類 ClassDemo11
    package com.siberiadante.kotlinforandroid.kotlin.demop10
    class ClassDemo11

    //二、新建一個 ExtendFunction.kt 文件,在改文件中建立 ClassDemo11 的擴展函數
    package com.siberiadante.kotlinforandroid.kotlin.demop10
    fun ClassDemo11.showMsg(msg: String) {
    // ClassDemo11 的擴展函數
    }
  • 要使用所定義包以外的一個擴展, 經過import導入擴展的函數名進行使用;
//ClassDemo12 中使用擴展函數
    package com.siberiadante.kotlinforandroid.kotlin
    //常規導入
    import com.siberiadante.kotlinforandroid.kotlin.demop10.ClassDemo11
    import com.siberiadante.kotlinforandroid.kotlin.demop10.showMsg
    //導入demop10下的一切
    //import com.siberiadante.kotlinforandroid.kotlin.demop10.*

    class ClassDemo12 {//調用擴展函數
        fun main(classDemo11: ClassDemo11) {
            classDemo11.showMsg("調用另外一個類的擴展函數")
        }
    }

擴展聲明爲成員

  • 在一個類的內部能夠爲另外一個類聲明擴展,在這個擴展中,有個多個隱含的接收者,其中擴展方法定義所在類的實例稱爲分發接收者,而擴展方法的目標類型的實例稱爲擴展接受者;
class ClassA {//擴展接收者
        fun showMsg() { println("ClassA showMsg") }
    }

    class ClassB {//分發接收者
        fun showMsg() { println("ClassB showMsg") }

        fun ClassA.printMsg() {
        // 爲 ClassA 聲明的擴展函數
        }
    }
  • 調用某一個函數,而該函數在分發接受者和擴展接受者均存在,則以擴展接收者優先;要引用分發接收者的成員須要使用限定的 this 語法;
class ClassA {//擴展接收者
        fun showMsg() { println("ClassA showMsg") }
    }

    class ClassB {//分發接收者
        fun showMsg() { println("ClassB showMsg") }

        fun ClassA.printMsg() {
            showMsg()   //擴展接收者(ClassA)的函數
            this@ClassB.showMsg()   //分發接收者(ClassB)的函數;語法:this@分發接收者.函數
        }
    }
  • 以成員的形式定義的擴展函數, 能夠聲明爲 open , 並且能夠在子類中覆蓋;
open class ClassC

    open class ClassC1 : ClassC()

    open class ClassD {
        open fun ClassC.showMsg() {//ClassC 的擴展函數
            print("ClassC msg --- ClassD")
        }

        open fun ClassC1.showMsg() {//ClassC1 的擴展函數
            print("ClassC1 msg --- ClassD")
        }

        fun printMsg(c: ClassC) {
            c.showMsg()//調用ClassC 的擴展函數
        }
    }

    class ClassD1 : ClassD() {
        override fun ClassC.showMsg() {
            print("ClassC msg --- ClassD1")
        }

        override fun ClassC1.showMsg() {
            print("ClassC1 msg --- ClassD1")
        }
    }

    fun main9() {
        //ClassD調用ClassC的showMsg
        ClassD().printMsg(ClassC()) // 輸出:ClassC msg --- ClassD
        //調用ClassD1調用本身重載的ClassC的showMsg
        ClassD1().printMsg(ClassC())    //輸出:ClassC msg --- ClassD1
        //ClassD調用printMsg,printMsg受ClassC限制
        ClassD().printMsg(ClassC1())    //輸出:ClassC msg --- ClassD
    }
相關文章
相關標籤/搜索