文章目錄
一、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表示=,負數表示<。