題外話:全書的目錄以及主要內容已經公開,可在我公衆號【技術實驗室】的歷史推送文章查看
已經公開章節:
第一部分——快速上手
第一章·啓程
第二章·基本語法
第三章·Kotlin 與 Java 混編
第二部分——開始學習 Kotlin
第四章·類與對象(上)
Kotlin 程序是什麼樣子的?如果瀏覽過本書,你會看到許多例子。很有可能你覺得 Kotlin 語言有點古怪,充滿了var field: String
這樣的語法。然而讀完本章後,你將不再對這些語法感到陌生,甚至很可能喜歡上它們。
2.1 變量
讓我們來看一個很簡單的程序。
fun main(args: Array<String>) {
var quantity = 5
val price: Double = 20.3
val name: String = "大米"
println("單價:$price")
println("數量:$quantity")
println("產品:$name 總計:${quantity * price}")
}
上面的代碼中,首先創建了一個名爲quantity
的變量用以表示產品的數量,並初始化爲 5。
一個值爲 20.3 的常量price
,用來表示產品的單價。
一個表示產品名字的字符串常量name
。
通過這段代碼我們可以看到,Kotlin 語言聲明一個變量使用關鍵字var
,聲明一個常量使用val
,聲明時 Kotlin 語言是可以自動推測出字段類型的,例如上面代碼中的var quantity = 5
會被認爲是Int
類型,但如果你希望它是一個Double
類型,則需要顯示聲明類型,例如var quantity: Double = 5
。
2.2 語句
2.2.1 in關鍵字的使用
判斷一個對象是否在某一個區間內,可以使用in關鍵字
//如果存在於區間(1,Y-1),則打印OK
if (x in 1..y-1)
print("OK")
//如果x不存在於array中,則輸出Out
if (x !in 0..array.lastIndex)
print("Out")
//打印1到5
for (x in 1..5)
print(x)
//遍歷集合(類似於Java中的for(String name : names))
for (name in names)
println(name)
//如果names集合中包含text對象則打印yes
if (text in names)
print("yes")
2.2.2 when表達式
類似於 Java 中的 switch,但是 Kotlin 更加智能,可以自動判斷參數的類型並轉換爲響應的匹配值。
fun cases(obj: Any) {
when (obj) {
1 -> print("第一項")
"hello" -> print("這個是字符串hello")
is Long -> print("這是一個Long類型數據")
!is String -> print("這不是String類型的數據")
else -> print("else類似於Java中的default")
}
}
2.2.3 智能類型推測
判斷一個對象是否爲一個類的實例,可以使用is關鍵字
與 Java 中的instanceof
關鍵字類似,但在 Kotlin 中如果已經確定了一個對象的類型,可以在接下來的代碼塊中直接作爲這個確定類型使用。
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// 做過類型判斷以後,obj會被系統自動轉換爲String類型
return obj.length
}
//同時還可以使用!is,來取反
if (obj !is String){
}
// 代碼塊外部的obj仍然是Any類型的引用
return null
}
2.2.4 空值檢測
Kotlin 是空指針安全的,也就意味着你不會再看到那惱人的空指針異常。
例如這句代碼 println(files?.size)
,只會在files
不爲空時執行。
以及,你可以這樣寫
//當data不爲空的時候,執行語句塊
data?.let{
//...
}
//相反的,以下代碼當data爲空時纔會執行
data?:let{
//...
}
2.3 函數
2.3.1 函數的聲明
函數使用關鍵字fun
聲明,如下代碼創建了一個名爲say()
的函數,它接受一個String
類型的參數,並返回一個String
類型的值
fun say(str: String): String {
return str
}
同時,在 Kotlin 中,如果像這種簡單的函數,可以簡寫爲
fun say(str: String): String = str
如果是返回Int
類型,那麼你甚至連返回類型都可以不寫
fun getIntValue(value: Int) = value
2.3.2 函數的默認參數
你也可以使用默認參數來實現重載類似的功能
fun say(str: String = "hello"): String = str
這時候你可以調用say()
,來得到默認的字符串 "hello"
,也可以自己傳入參數say("world")
來得到傳入參數值。
有時參數非常多的時候,也可以使用多行參數的寫法,它們是相同的
fun say(firstName: String = "Tao",
lastName: String = "Zhang"){
}
2.3.3 變參函數
同 Java 的變長參數一樣,Kotlin 也支持變長參數
//在Java中,我們這麼表示一個變長函數
public boolean hasEmpty(String... strArray){
for (String str : strArray){
if ("".equals(str) || str == null)
return true;
}
return false;
}
//在Kotlin中,使用關鍵字vararg來表示
fun hasEmpty(vararg strArray: String?): Boolean{
for (str in strArray){
if ("".equals(str) || str == null)
return true
}
return false
}
2.3.4 擴展函數
你可以給父類添加一個方法,這個方法將可以在所有子類中使用
例如,在 Android 開發中,我們常常使用這樣的擴展函數:
fun Activity.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, message, duration).show()
}
這樣,我們就可以在每一個Activity
中直接使用toast()函數了。
2.3.5 將函數作爲參數
Kotlin 中,可以將一個函數作爲參數傳遞給另一個函數
fun lock<T>(lock: Lock, body: () -> T ) : T {
lock.lock()
try {
return body()
}
finally {
lock.unlock()
}
}
上面的代碼中,我們傳入了一個無參的 body() 作爲 lock() 的參數,
2.4 小結
最後,我們用一段代碼來總結本章內容,你能看懂嗎?
fun main(args: Array<String>) {
val firstName: String = "Tao"
val lastName: String? = "Zhang"
println("my name is ${getName(firstName, lastName)}")
}
fun hasEmpty(vararg strArray: String?): Boolean {
for (str in strArray) {
str ?: return true
}
return false
}
fun getName(firstName: String?, lastName: String? = "unknow"): String {
if (hasEmpty(firstName, lastName)) {
lastName?.let { return@getName "${checkName(firstName)} $lastName" }
firstName?.let { return@getName "$firstName ${checkName(lastName)}" }
}
return "$firstName $lastName"
}
fun checkName(name: String?): String = name ?: "unknow"