Kotlin學習快速入門(7)——擴充套件的妙用

2022-07-03 18:01:33

原文地址: Kotlin學習快速入門(7)——擴充套件的妙用 - Stars-One的雜貨小窩

之前也模模糊糊地在用這個功能,也是十分方便,可以不用繼承,快速給某個類增加新的方法,本篇便是來講解下Kotlin中擴充套件這一概念的使用

說明

先解釋一下,擴充套件的說明,官方檔案上解釋:

Kotlin 能夠擴充套件一個類的新功能,而無需繼承該類或者使用像裝飾者這樣的設計模式

簡單來說,就是可以不用繼承來讓一個類多出一個方法或屬性(成員變數),可能這樣說比較抽象,我們以一個簡單的例子來說

比如說,我們需要用到以下功能:

判斷String物件是否其是否為null或未空白字串,如果為null或空白字串,則返回true,否則返回false

此功能挺好實現,但我們想要實現此功能,無非就是3種方法:

  1. 寫個工具類StringUtil,然後傳遞有個String物件進去,方法返回
  2. 寫個新的類,讓其繼承於String類,之後再新增方法
  3. 用裝飾者模式,擴充套件類(這裡不多解釋裝飾者模式,可以自己百度查閱下資料)

但上面的方法,估計第一種各位都明白,也是十分簡單,但使用起來還是比較麻煩,還得將物件作為入參傳遞,如果使用Kotlin的擴充套件特性,還能變得更加簡單

而剩下兩種,改動均是較大,一般得看情況使用,也是不太推薦

擴充套件方法

我們以剛才上述說的功能為例,實現判斷String物件是否其是否為null或未空白字串,如果為null或空白字串,則返回true,否則返回false此功能

語法及使用

首先,顯示講解下語法

fun 類名.方法名(參數列...):返回值{
    
}

看起來稍微有些抽象,我們直接上範例:

fun String.isBlankOrNullString(): Boolean {
    return this == null || this.trim().length == 0
}

需要注意的是,方法裡的this就是當前呼叫此方法的String物件

擴充套件方法使用:

fun main(args: Array<String>) {
    val str = ""
    println(str.isBlankOrNullString())
}

PS: 這裡的擴充套件方法寫在了頂層,是全域性可用的

注意點

  1. 擴充套件方法會區分作用域(全域性和區域性)
  2. 類中存在於擴充套件方法同名同參數列,相當於過載,此時以擴充套件方法為主
  3. 擴充套件方法可接收可空型別

擴充套件方法作用域

擴充套件方法的宣告位置,會決定此擴充套件方法的作用域

如下面範例:

fun main() {
    val str = ""
    println(str.isBlankOrNullString())
}

class User {
    val str = ""
}

fun String.isBlankOrNullString(): Boolean {
    return this == null || this.trim().length == 0
}

我們將方法寫在了最外層(即與class關鍵字同級),此時,我們可以在任意的類中呼叫此方法

但如果我們稍微改一下,如下:

fun main() {
    val str = ""
    //這裡會報錯!!
    //println(str.isBlankOrNullString())
}

class User {
    val str = ""

    fun sayHello() {
        //類中可以正常使用
        str.isBlankOrNullString()
    }

    fun String.isBlankOrNullString(): Boolean {
        return this == null || this.trim().length == 0
    }

}

擴充套件方法過載問題

由於是宣告方法,可能會出現方法名重名的情況,即我們Java基礎中說到的過載關係

這裡,如果出現了過載的情況(方法名和參數列相同),會以類中的方法為主(即會忽略掉擴充套件方法)

上面此句,是根據檔案上總結得來的,實際上也是測試通過

fun main() {
    Example().printFunctionType()
}

class Example {
    fun printFunctionType() { println("Class method") }
}

fun Example.printFunctionType() { println("Extension function") }

最後輸出的是Class method

但這裡有個奇怪的情況,我以String的擴充套件為例,測試發現與上述結論不一致!!

以下是我的測試程式碼:

fun main() {
    val str = ""
    println(str.isNullOrBlank())
}

fun String.isNullOrBlank(): Boolean {
    println("進入我們的方法裡")
    return this == null || this.trim().length == 0
}

最終輸出:

進入我們的方法裡
true

看著列印,這明顯就是進到我們定義的擴充套件方法裡啊