什麼是擴展函數
- 擴展函數數是指在一個類上增長一種新的行爲,咱們甚至沒有這個類代碼的訪問權限;
- 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
}