Kotlin-簡約之美-進階篇(十):擴展函數和擴展屬性

@[toc]
擴展函數給本來單薄的類添加了許多功能,今天我們來詳細看一下擴展函數和擴展屬性到底是什么,應該怎么用。

擴展函數和擴展屬性的實現

我們都知道,Java 中,只有一個類型的成員屬性和成員方法才能用“對象.屬性 / 方法()”的方式調用,一個類型的對象是絕對不可能通過這種方法調用其他類里定義的方法(除非存在繼承或實現關系)。而 Kotlin 提供的擴展函數和擴展屬性打破了這一規則,它是怎么實現的呢?

首先看例子:

// Test.kt
fun <T> MutableList<T>.swap(indexA: Int, indexB: Int) {
    val temp = this[indexA]
    this[indexA] = this[indexB]
    this[indexB] = temp
}

val Int.isOdd: Boolean
    get() = this and 1 == 1

我們在這里定義一個擴展函數 swap,它的接收者是 MutableList,作用是調換傳入的兩個索引對應的值。然后給 Int 類定義了一個擴展屬性 isOdd,用來檢查這個 Int 是不是奇數。

這時我們就可以這樣調用它們了:

val list = mutableListOf(1, 2, 3)
list.swap(0, 1)
println(list)
// [2, 1, 3]

val n = 3
println(n.isOdd)
// true

但想要在 Java 中調用它們,就要這么寫了:

// import TestKt
List<Integer> list = new ArrayList<>();
list.add(1); list.add(2); list.add(3);
TestKt.swap(list, 0, 1);
System.out.println(list);

int n = 3;
println(TestKt.isOdd(n));

實際上,所有的擴展函數和擴展屬性都會被編譯成一個方法,這個方法的第一個參數就是擴展的接收者,然后才是其它各個參數。對于擴展屬性來說 ,因為編譯后這個屬性并不存在,所以不能像一般的類屬性那樣對它進行初始化,而是要自定義 getter 和 setter 來訪問它。

為什么要用擴展函數和擴展屬性

Java 里有許多工具類,比如 Collections、Arrays、Objects 等等,它們提供了一系列靜態方法來充當工具函數,通過參數傳入被操作的對象,既不直觀又冗長無比。

比如對于 Integer.parseInt(String s),Kotlin 就用一個擴展函數替代了它:

inline fun String.toInt() = java.lang.Integer.parseInt(this)

雖然還是調用這個方法,但這樣定義有兩個好處,一是減少了代碼量,二是形成了一個統一的標準,所有其他基本類型都可以重載這個方法,實現同一個行為。

從另一個角度來看,Kotlin 鼓勵開發者 盡量精簡類的定義,一個類只定義框架,工具函數可以通過外部擴展一點點地添加,盡量不改動原有的類。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容