在 Java 中,想要擴展類的功能,可是又不想直接改原來的類時,通常會採用繼承、組合(裝飾者模式)等方式來實現。而 Kotlin 中支持對類的屬性和函數進行擴展,在類外增長原來類的屬性和函數,能夠方便地實如今原來的類上添加新功能。後端
函數擴展的格式爲:bash
fun <類名>.<擴展函數名>([參數列表])<:返回類型>{
}
複製代碼
在 Android 開發中,咱們常常須要在 Activity 中彈出 Toast,每次要寫:Toast.makeText(this, "text", Toast.LENGTH_SHORT).show();
這麼一長串很累,一般都會封裝一個工具類來簡化一下調用: ToastUtils.makeToast("text");
。函數
在 Kotlin 中,有了擴展函數,咱們能夠更加方便優雅地彈 Toast,工具
在一個擴展文件中,對 Context 類加一個擴展函數,由於 Activity 是 Context 的子類,也能夠直接調用。ui
fun Context.showToast(content: String) {
Toast.makeText(this, content, Toast.LENGTH_SHORT).show()
}
複製代碼
這樣在 Activity 中咱們就能夠這樣來彈 Toast:this
button.setOnClickListener{
showToast("text")
}
複製代碼
是否是很是方便簡潔?spa
在擴展函數中,可使用 this
關鍵字指代調用這個函數的對象。code
擴展函數是靜態解析的對象
擴展函數時靜態解析的,具體調用哪個類的函數,由調用函數的表達式類型決定,而不是由表達式運行時的動態類型決定。繼承
open class Shape
class Rectangle: Shape()
fun Shape.getName() = "Shape"
fun Rectangle.getName() = "Rectangle"
fun printClassName(s: Shape) { //類型是Shape
println(s.getName())
}
printClassName(Rectangle())
//運行結果
Shape
複製代碼
和成員函數重名
若是擴展函數和類的成員函數一致時,優先調用成員函數。
class C {
fun foo() { println("成員函數") }
}
fun C.foo() { println("擴展函數") }
fun main(){
var c = C()
c.foo()
}
//運行結果
成員函數
複製代碼
空對象的擴展
在擴展函數內, 能夠經過 this == null
來判斷接收者是否爲 null。這樣,即便接收者爲 null,也能夠調用擴展函數。
fun Any?.toString(): String {
if (this == null) return "null"
// 空檢測以後,「this」會自動轉換爲非空類型,因此下面的 toString()
// 解析爲 Any 類的成員函數
return toString()
}
fun main(){
var t = null
println(t.toString())
}
//運行結果
null
複製代碼
Java 中調用擴展函數
經過文件名+Kt.函數名(擴展類的對象,完整的其餘參數)
來在 Java 中調用擴展函數(至關於調用工具類的靜態方法)。
例如以前的 Toast 示例,該擴展函數寫在 Utils.kt 文件下,則在 Java 代碼中應該這樣調用這個函數。
UtilsKt.showToast(MainActivity.this, "Hello");
複製代碼
Kotlin 也支持對屬性進行擴展。
val <T> List<T>. lastIndex: Int
get() = size - 1
複製代碼
因爲擴展沒有實際的將成員插入類中,所以對擴展屬性來講後端變量
是無效的。這就是爲何擴展屬性不能有初始化器。他們的行爲只能由顯式提供的 getters/setters 定義。
擴展函數只能被聲明爲 val
。
能夠給類的伴生對象定義擴展函數和屬性。
伴生對象經過類名.
的形式調用伴生對象,伴生對象聲明的擴展函數,經過用類名限定符來調用:
class MyClass {
companion object { } // 將被稱爲 "Companion"
}
fun MyClass.Companion.foo() {
println("伴隨對象的擴展函數")
}
val MyClass.Companion.no: Int
get() = 10
fun main(args: Array<String>) {
println("no:${MyClass.no}")
MyClass.foo()
}
//運行結果
no:10
伴隨對象的擴展函數
複製代碼