Kotlin 語言學習(4) - 數據類、類委託 及 object 關鍵字
Kotlin 語言學習(5) - lambda 表達式和成員引用
一、本文概要
二、在 kotlin 中創建集合
在kotlin
中,創建HashSet
、ArrayList
和HashMap
的方法如下:
通過打印這些集合的類型,可以看到是採用的標準的Java
集合類:
這麼做的原因,是因爲使用標準的Java
集合使kotlin
可以更容易地與Java
代碼交互。當從Kotlin
調用Java
函數的時候,不用轉換它的集合類來匹配Java
的類,反之亦然。
在這些集合對象上,我們除了可以使用Java
當中定義的基本函數以外,還可以使用kotlin
提供的擴展方法,例如下面的last
和max
:
運行結果爲:
三、讓函數更好調用
下面,我們定義一個函數,它的作用的是打印集合當中的元素,並指定元素之間添加分隔符、前綴和後綴:
運行結果爲:
3.1 命名參數
在上面的例子中,我們指定了分隔符、前綴和後綴三個參數,但是對於這個函數的使用者來說,如果不去看這些函數的聲明,很難看出這些String
類型的含義,這時候就可以使用 命名參數 的方法來調用,這有兩點好處:
- 增加函數的可讀性
- 以想要的順序指定需要的參數
下面,我們使用命名參數,並在不改變函數定義的情況下,改變傳入參數的順序,也可以得到和上面相同的運行結果:
對於命名參數,有以下幾點需要注意:
- 如果在調用一個函數時,指明瞭一個參數的名稱,那它之後的所有參數都要表明名稱。
- 當調用
Java
函數時,不能使用命名參數
3.2 默認參數值
在kotlin
中,可以在聲明函數的時候,指定參數的默認值,這樣就可以避免創建重載的函數,例如上面的例子,我們可以在 定義函數 時,指定三個String
的默認值,而在 調用函數 的時候,如果沒有傳遞這些參數,那麼將會採用默認值:
運行結果爲:
友情提示:
- 如果使用常規的調用語法時,必須按照函數聲明中定義的參數順序來給定參數,可以省略的只有排在末尾的參數。
-
如果使用命名參數,可以省略中間的一些參數,也可以以你想要的任意順序只給定你需要的參數,例如我們只修改前綴和後綴,分隔符仍然採用默認值:
運行結果爲:
3.3 頂層函數和屬性
在Java
中,所有的代碼都需要寫作類的函數,但是在項目中,很多代碼並不能歸屬到類中,這時候我們一般會定義一個xxUtils
類,並在其中聲明static
的靜態方法。
在kotlin
中,我們可以把這些函數直接放到代碼文件的頂層,不用從屬於任何的類,這些放在文件頂層的函數仍然是包內的成員,如果你需要從包外訪問它,則需要import
,但不再需要額外包一層。
3.3.1 在 Java 中調用頂層函數
如果我們想要在Java
中調用這些頂層函數,則需要通過Kotlin
根據包含函數的文件的名稱生成的類,例如我們有兩個文件:
KotlinMethod.kt
:
fun kotlinFunc() {}
JavaCallKotlin.java:
public class JavaCallKotlin {
public JavaCallKotlin() {
KotlinMethodKt.kotlinFunc();
}
}
前者包含一個頂層函數,那麼在Java
中,就會根據該文件名生成一個{文件名}Kt
的類型,再通過這個類來調用這個頂層函數。
如果不想使用默認的類名,可以在.kt
文件的開頭加上@file:JvmName("類名")
的註解。
3.3.2 在 Java 中調用頂層屬性
和函數一樣,屬性也可以放到文件的頂層。默認情況下,頂層屬性和其他任意的屬性一樣,是通過訪問器暴露給Java
使用的(如果是val
就只有一個getter
,如果是var
就對應getter
和setter
)。如果想要把一個常量以public static final
的屬性暴露給Java
,可以使用const
來修飾它。
package com.demo.lizejun.kotlinsample.chapter1
//不可變。
val kotlinVal = "kotlinValue"
//可變。
var kotlinVar = "kotlinVariable"
//常量。
const val kotlinConst = "kotlinConst"
//頂層函數。
fun kotlinFunc() {}
在Java
中,分別通過以下幾種方式來訪問或者修改這幾個頂層屬性:
package com.demo.lizejun.kotlinsample.chapter3;
import com.demo.lizejun.kotlinsample.chapter1.KotlinMethodKt;
public class JavaCallKotlin {
public JavaCallKotlin() {
KotlinMethodKt.kotlinFunc();
//不可變。
KotlinMethodKt.getKotlinVal();
//可變。
KotlinMethodKt.setKotlinVar("newKotlinVar");
KotlinMethodKt.getKotlinVar();
//常量。
String kotlinConst = KotlinMethodKt.kotlinConst;
}
}
四、擴展函數和屬性
擴展函數 其實是一個類的成員函數,只不過它定義在類的外面,我們所需要做的,就是在聲明擴展函數的時候,把需要擴展的類或者接口的名稱,放到它的前面,用來調用這個擴展函數的對象,就叫做 接收者對象。
在擴展函數中,可以直接訪問被擴展的類的其它方法和屬性,就好像是在這個類自己的方法中訪問它們的一樣,但是擴展函數不允許你打破它的封裝性,擴展函數不能訪問私有的或者是受保護的成員。
4.1 擴展函數的定義和使用
下面我們給String
類添加一個擴展函數,返回它的最後一個字符:
運行結果爲:
4.2 在 Java 中使用擴展函數
如果需要在Java
中調用擴展函數,那麼把接收者對象作爲第一個參數傳進去即可:
//接收者對象作爲第一個參數。
char lastChar = KotlinMethodKt.last("Kotlin");
4.3 不能重寫的擴展函數
這裏假設我們有兩個類,View
和Button
,其中Button
繼承於View
,我們給這兩個類都添加一個名爲showOff
的擴展函數。
運行結果爲:
儘管實際上這個變量是一個Button
的對象,但是Kotlin
會把擴展函數當做靜態函數來對待,因此 擴展函數不存在重寫。
4.4 擴展屬性
擴展屬性提供了一種方法,用來擴展類的API
,可以用來訪問屬性,用的是屬性語法而不是函數的語法,儘管他們被稱爲屬性,但它們沒有任何狀態,因爲沒有合適的地方來存儲它們。
現在,我們給StringBuilder
添加一個可讀寫的屬性lastChar
,用於獲取或者改變它的最後一個字符,包含以下幾點要素:
- 擴展屬性以
var/val
關鍵字開頭; - 指定擴展屬性的名字、類型;
- 如果是
var
那麼提供get()/set(value : T)
方法,而如果是val
屬性,那麼提供get()
方法,其中T
爲屬性的類型。
運行結果爲:
五、可變參數、中綴調用和庫的支持
使用關鍵字 vararg,可以用來聲明一個函數將有可能有任意數量的參數,下面例子中,我們定義一個可以接收可變數量Int
類型的函數,之後和在Java
中一樣,它會被轉換爲[I
的整型數組類型:
運行結果爲:
而如果我們已經將參數打包成一個數組,這時候如果想要將它傳遞給一個接收可變參數的函數,那麼需要先通過*
操作符進行解包:
運行結果爲:
5.2 中綴調用
中綴調用 不是特殊的內置結構,而是一種特殊的函數調用。在中綴調用中,沒有添加額外的分隔符,函數名稱是直接放在目標對象名稱和參數之間。例如我們聲明瞭一個to
函數。
//一般函數調用。
1.to("One")
//中綴調用。
1 to "One"
中綴調用可以與 只有一個參數的函數 一起使用,無論是普通的函數還是擴展函數,要允許使用中綴符號調用函數,需要使用infix
修飾符來標記它,下面是一個創建Person
的函數,我們採用了擴展函數的方法,這裏的Any
是Kotlin
中所有類的父類,和Java
中的Object
相同:
運行的結果爲:
六、字符串處理
6.1 分割字符串
在Java
中,我們會使用split
來分割字符串,它接受一個正則表達式作爲參數。但是當我們想分割"."
時,會得到一個空的數組,因爲.
號表示任何字符的正則表達式。
而在kotlin
中,它提供了一個接受Regex
類型的重載函數,這樣確保了當有一個字符串傳遞給這些函數的時候,不會被當做正則表達式,我們可以使用擴展函數toRegex
將字符串轉換爲正則表達式。
運行結果爲:
6.2 正則表達式
假設有下面這個字符串:
/Users/yole/kotlin-book/chapter.adoc
我們需要通過這個字符串獲取到chapter.adoc
的目錄、文件名和擴展名,如果使用擴展函數,那麼代碼如下:
運行結果爲:
下面是使用正則表達式的做法:
這個正則表達式將一個路徑分爲三個由斜線和點分隔的組:
.
模式從字符串的一開始就進行匹配,所以第一組(.+)
包含最後一個斜線之前的子串,這和子串包含所有前面的斜線,因爲它們匹配”任何字符“的模式。- 第二組包含最後一個點之前的子串
- 第三組包含剩餘部分
七、局部函數
在Java
的一個函數當中,有可能存在重複代碼,例如在註冊模塊中,可能需要校驗輸入的多個字段是否有效,那麼校驗的邏輯就可以提取出一個函數,而Kotlin
就提供了一種方法:可以在函數中嵌套這些提取的函數,局部函數定義方式和普通函數是相同的。
運行的結果爲: