Kotlin 教程(一)

一、Hello World

fun main() {
    println("Hello world")
}

二、基礎語法

2.1 變量聲明

var a1: Int = 0 // 可變參數
var a2 = 0 // Kotlin 有出色的類型推斷機制,變量類型可以省略
val b = 1 // 不可變參數

2.2 函數聲明

// 函數名 test,攜帶參數 a,返回類型 String
fun test1(a: Int): String {
    return a.toString()
}

// 如果函數體只有一行,可用“=”表示,返回類型可省略
fun test2(a: Int) = a.toString()

2.3 條件語句

if 條件

// if 語句擁有返回值,返回值就是每個條件中最後一行代碼的返回值
fun max(a: Int, b: Int) = if (a > b) a else b

when 條件

// when語句非常靈活,可以傳入一個任意類型的參數,也可以什麼都不傳
fun getSeason(month: Int) = when (month) {
    // 判斷是否在範圍內
    in 3..5 -> "Spring"
    in 6..8 -> "Summer"
    in 9..11 -> "Autumn"
    // 多個條件用","連接
    12, in 1..2 -> "Winter"
    else -> throw IllegalArgumentException("The month value is out of range")
}

2.4 循環語句

// in Range,輸出 1~10
for (i in 1..10) {
    println(i)
}
// until表示左開右閉,這在遍歷列表下標時非常好用。比如這裏指[0,10),輸出 0~9
for (i in 0 until 10) {
    println(i)
}
// downTo 逆序,輸出 10~1
for (i in 10 downTo 1) {
    println(i)
}
// step 設置步長,輸出 1 3 5 7 9
for (i in 1..10 step 2) {
    println(i)
}
// while 循環,輸出 1~10
var i = 0
while (i++ < 10) {
    println(i)
}

2.5 構造函數

// 默認是一個無參構造函數
class Person

// 攜帶參數的構造函數
class Person(name: String, age: Int, gender: String)

// 參數前帶有 val 或者 var 時,會在類中生成一個相應的字段。否則參數只能在構造函數中使用
class Person(val name: String, var age: Int, gender: String)

// 每個參數都可以設置默認值,沒有設定默認值的參數必須在構建時傳入
class Person(name: String, age: Int = 0, gender: String = "secret")

// 設定了默認值的構造函數如果加上 @JvmOverloads 註解,在 Java 類中使用時,就會生成對應的構造方法。
// Kotlin 中 @JvmXxxx 這一類註解都是爲了兼容 Java 使用的,純 Kotlin 開發不需要這些註解
class Person @JvmOverloads constructor(name: String, age: Int = 0, gender: String = "secret")

// 使用 constructor 自定義構造函數
class Person {
    constructor(name: String, age: Int, gender: String)
    constructor(name: String, gender: String)
}

2.6 可見性修飾符

修飾符 Java Kotlin
public 所有類可見 所有類可見(默認)
private 當前類可見 當前類可見
protected 當前類、子類、同一包路徑下的類可見 當前類、子類可見
default 同一包路徑下的類可見(默認)
internal 同一模塊中的類可見

三、特性

3.1 數據類

// 自動生成 equals、hashCode、toString 方法
data class Person(val name: String, val age: Int)

// 輸出 Person(name=name, age=12)
println(Person("name", 12))
// 輸出 true
println(Person("name", 12) == Person("name", 12))

3.2 單例

// 使用 object 關鍵字就表示這是一個單例類
object Singleton

3.3 集合

// 初始化一個列表 [1, 2, 3]
val list = listOf(1, 2, 3)
// forEach 逐個遍歷列表, 輸出 1 2 3
list.forEach {
    println(it)
}
// map 將列表轉換成 ["1","2","3"]
val strList = list.map { it.toString() }
// 排序 [1, 2, 3]
val sortedList = list.sorted()
// 按某個值排序 [1, 2, 3]
val sortedList = list.sortedBy { it }
// 過濾出符合條件的列表 [3]
val filterList = list.filter { it > 2 }
// 是否存在某個值滿足條件 true
val exist1 = list.any { it == 1 }
// 是否所有值都滿足條件 false
val allAbove1 = list.all { it > 1 }

// 可變列表
val mutableList = mutableListOf(1, 2, 3)
// 其他列表類型 Map、HashMap、Set等,操作類似
val map = mapOf(1 to "one", 2 to "two", 3 to "three")
val hashMap = hashMapOf(1 to "one", 2 to "two", 3 to "three")
val set = setOf(1, 2, 3)

3.4 空檢查

// 變量類型後加 ? 表示這個變量爲可空類型,不加的話表示不可空類型,不可空類型不能設置成 null
val string1: String? = "Android"
val string2: String? = null
// "?." 表示不爲空時才執行後面的代碼,輸出 ANDROID
println(string1?.toUpperCase())
// string2 爲空,所以 toUpperCase 不執行,輸出 null
println(string2?.toUpperCase())
// "?:" 表示爲空時才取後面的值,string1 不爲空,輸出 Android
println(string1 ?: "it's null")
// string2 爲空,輸出 it's null
println(string2 ?: "it's null")

// "!!" 表示斷定它不爲空,不進行空檢查,不建議使用,可能導致空指針
println(string1!!.toUpperCase())

3.5 字符串內嵌

val string1: String? = "Android"
val string2: String? = null
// 使用 "$" 內嵌變量,使用 "${}" 內嵌表達式
// 輸出 string1 = Android, is string2 null ? true
println("string1 = $string1, is string2 null ? ${string2 == null}")

3.6 標準函數

let

val string1: String? = "Android"
// 將變量攜帶到代碼塊中執行一段代碼,代碼塊最後一行作爲返回值。
// b = "ANDROID"
val b = a.let {
    println(it)
    it.toUpperCase()
}

run

val a = "Android"
// 將變量攜帶到代碼塊中執行一段代碼,並且代碼塊中此變量作爲上下文,也就是說代碼塊裏面可以直接調用 a 類中的函數。代碼塊最後一行作爲返回值。
// b = "ANDROID"
val b = a.run {
    println(this)
    toUpperCase()
}

with

val a = "Android"
// with 和 run 效果一模一樣,只不過是調用方式的區別:run 是直接用參數調用 run 方法,而 with 可以直接使用,參數傳到 with 裏
// b = "ANDROID"
val b = with(a) {
    println(this)
    toUpperCase()
}

apply

val a = mutableListOf(1)
// 和 with、run 類似,將變量攜帶到代碼塊中執行一段代碼,並且代碼塊中此變量作爲上下文,不同的是 apply 將調用對象本身作爲返回值
// b = [1, 2, 3]
val b = a.apply {
    add(2)
    add(3)
}

repeat

// repeat 表示重複 n 次,輸出 0~9
repeat(10) {
    println(it)
}

takeIf

val a = 2
// 如果 a 滿足條件,則取 a,否則取 null,這裏 b 的類型爲 Int?
// b 的值爲 2
val b = a.takeIf { a > 1 }

takeUnless

val a = 2
// 與 takeIf 相反
// c 的值爲 null
val c = a.takeUnless { a > 1 }

3.7 靜態方法

// 上文中講到的單例類中的方法都是靜態方法
object Singleton {
    fun test() {
        println("it's a static method")
    }
}

class Person {
    // 每個類都可以定義一個伴生對象,伴生對象中的方法都是靜態方法
    companion object {
        fun test() {
            println("it's a static method")
        }
    }
}

// 不在任何一個類中的方法被稱爲頂層方法,頂層方法都是靜態方法
fun test() {
    println("it's a static method")
}


object Singleton {
    // 放在類中的靜態方法添加 @JvmStatic 註解後,在 Java 代碼中就可以像靜態方法那樣調用了
    @JvmStatic
    fun test() {
        println("it's a static method")
    }
}

3.8 延遲初始化

// 使用 lateinit 關鍵字表示待會再初始化此變量,這個關鍵字在定義非空類型時非常有用。
// 否則我們不得不將全局變量申明爲可空類型併爲其賦值爲 null,導致使用時的不方便
lateinit var a: String

// 判斷延遲初始化變量是否已經被初始化
::a.isInitialized

3.9 密封類

不使用密封類存在的問題

// 定義了一個 Result 接口
interface Result
// 定義了兩個子類實現了 Result 接口
class Success : Result
class Failure : Result

fun test(result: Result) = when (result) {
    is Success -> 1
    is Failure -> 2
    // 我們知道這裏的 result 只可能是 Success 或者 Failure,但 when 語句需要返回值時,必須保證每一種對應的情況都有一個返回值。所以我們不得不編寫這個多餘的 else 條件,才能保證編譯通過
    else -> throw Exception("impossible")
}

使用密封類後

// sealed 關鍵字表示這是一個密封類
sealed class Result

class Success : Result()
class Failure : Result()

// when 語句中傳入密封類時,Kotlin 會自動檢測密封類有哪些子類,只要每個子類都處理了,就不再需要 else 語句了
fun test(result: Result) = when (result) {
    is Success -> 1
    is Failure -> 2
}

3.10 擴展函數

擴展函數使得我們很方便的爲一個類擴展新的方法

// 定義擴展函數很簡單,使用"類名.新方法名"即可。這裏我們定義的方法用來爲字符串後綴一個 "666"
fun String.add666(): String {
    return "${this}666"
}

fun main() {
    val a = "Android"
    val b = a.add666()
    // 輸出 Android666
    println(b)
}

3.11 運算符重載

class Person(val name: String) {
    // 使用 operator 關鍵字重載運算符,plus 方法表示重載 "+" 運算
    operator fun plus(person: Person): List<String> {
        return listOf(this.name, person.name)
    }
}

fun main() {
    val a = Person("小明")
    val b = Person("大明")
    // 重載後,就可以用 "+" 運算符來調用類中的 plus 方法
    val c = a + b
    // 輸出 [小明, 大明]
    println(c)
}

可重載的運算符以及對應的方法

運算符 對應方法
a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.rem(b)
a++ a.inc()
a– a.dec()
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()
a == b a.equals(b)
a > b a.compareTo(b)
a < b a.compareTo(b)
a >= b a.compareTo(b)
a <= b a.compareTo(b)
a…b a.rangeTo(b)
a[b] a.get(b)
a[b] = c a.set(b, c)
a in b b.contains(a)

其中,a.compareTo(b) 必須返回 Int,返回正數表示>,0表示=,負數表示<。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章