Kotlin 修煉手冊(7)Kotlin 的擴展

在 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
伴隨對象的擴展函數
複製代碼
相關文章
相關標籤/搜索