前言
kotlin同C#和Gson類似,能夠擴充一個類的心的功能而無需繼承該類或使用像對象修飾者這樣的任何類型的設計模式,這個通過叫擴充的特殊聲明完成,kotlin 支援擴充函數和擴充屬性。
擴充函數
聲明一個擴充函數,我們需要用一個接收者類型也就是被擴充的類型來作為他的字首,例如`
import java.lang.StringBuilder
fun main(args: Array<String>) {
val name = "栾小黑"
println(name.MyAppend("超級厲害"))
}
/***
* 對String這個類進行擴充 在原本的字元串後邊拼接字元串
* name 拼接的字元串内容
*/
fun String.MyAppend(name: String): String {
val stringBuilder = StringBuilder()
stringBuilder.append(this)
stringBuilder.append(name)
val result = stringBuilder.toString()
return result
}
擴充是靜态解析的
擴充不能真正的修改他們的擴充類。通過定義一個擴充,你并沒有在類中插入新的成員,僅僅是可以通過該類型的變量使用點的表達式調用這個函數。
我們像強調得失擴充函數是靜态分發的,即他們不是根據接收者類型的虛方法。這意味着調用的擴充函數是由函數調用所在的表達式的類型決定的,而不是由表達式運作的結果決定的
open class C
class D: C()
fun C.foo() = "c"
fun D.foo() = "d"
fun printFoo(c: C) {
println(c.foo())
}
printFoo(D())
這個例子會輸出c 因為調用的擴充函數隻取決于參數c的聲明類型,該類型是C類
備注:如果一個類定義有一個成員函數與一個擴充函數,而這兩個函數又有相同的接收者類型、相同的名字,都适用給定的參數,這種情況總是取成員函數。
//為String類添加一個擴充方法get()無論什麼時候都會傳回一個字元c
fun String.get(index: Int): Char {
return 'c'
}
fun main(args: Array<String>) {
val name = "栾小黑"
println( name.get(2))
}
此段代碼運作的結果是 “黑”說明調用的是String類自己的get方法,而不是我們寫的擴充方法。
可空接收者
注意可以為可空的接受者類型定義擴充。這樣的擴充可以在對象變量上調用,即使他的值是null,并且可以在函數體内部檢測 this==null,這能讓你在沒有檢測null的時候調用kotlin的toString(): 檢測發生在擴充函數的内部
fun Any?.toString(): String {
if (this == null) return "null"
return this.toString()
}
fun main(args: Array<String>) {
val nameTwo:String? = "hello world"
val nameTwo:String? = null
println(nameTwo.toString())
println(nameThree.toString())
}
該程式會輸出 hello world,null
擴充屬性
與函數類似,kotlin 支援擴充屬性:
val <T> List<T>.lastIndex:Int get() = size-1
注意:由于擴充沒有實際的将成員插入類中,是以對擴充屬性來說幕後字段是無效的。這就是為什麼擴充屬性不能有初始化器。他們的行為隻能由顯式提供的 getters/setters 定義。
聲明屬性的完整的文法是
var [:] [=<property_initializer>]
[ getter方法 ]
[ settter方法]
伴生對象的擴充
如果一個類又一個伴生對象,你也可以為伴生對象定義擴充函數的屬性:
class MyClass{
companion object{ } // 伴生對象
}
fun MyClass.Companion.foo(){...}
就像伴生對象的其他普通成員一樣,隻需要用類名做限定符去調用他們