課程地址:https://kaixue.io/kotlin-basic-1/
為項(xiàng)目添加 Kotlin 支持
根目錄下的 build.gradle
buildscript {
// 這里配置一個(gè)全局版本號
ext.kotlin_version = '1.3.31'
dependencies {
// 這里添加依賴
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
app 目錄下的 build.gradle
// 使用 kotlin 的 plugin
apply plugin: 'kotlin-android'
dependencies {
// 添加依賴
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
Kotlin 文件都是以 .kt 結(jié)尾的
變量
變量的聲明與賦值
var view : View
- 有一個(gè) var 關(guān)鍵字
- 變量名在前德绿,類型在后舷手,冒號分隔
- 結(jié)尾不需要分號
Kotlin 空安全設(shè)計(jì)
非空類型
- Kotlin 中變量是沒有默認(rèn)值的眉尸,需要手動初始化
- Kotlin 默認(rèn)聲明變量是非空的秒紧,不能賦值為 null
可空類型
- 聲明可空變量需要在類型右邊加一個(gè)問號栗恩,被稱為可空類型
var name: String? = null
- 調(diào)用可空類型變量時(shí)不能手動判斷是否為空透乾,需要使用 ?. ,被稱為「safe call」
view?.setBackgroundColor(Color.RED)
- 還有一種雙嘆號的寫法磕秤,被成為「斷言式寫法」乳乌,編譯器不再做檢查
view!!.setBackgroundColor(Color.RED)
關(guān)于空安全,最重要的是記住一點(diǎn):所謂「可空不可空」市咆,關(guān)注的全都是使用的時(shí)候汉操,即「這個(gè)變量在使用時(shí)是否可能為空」。
Kotlin 和 Java 的空安全設(shè)計(jì)兼容
- Kotlin 中調(diào)用 Java 中 @Nullable 變量
name?.length
- Java 中 @Nullable 和 @NonNull 注解可以自動轉(zhuǎn)化為 Kotlin 代碼
// Java
@Nullable
String name;
@NonNull
String value = "hello";
// Kotlin
var name: String? = null
var value: String = "hello"
延遲初始化
lateinit 關(guān)鍵字適用于聲明時(shí)不能賦值蒙兰,但是能保證使用之前一定會賦值的場景磷瘤,例如 Activity 中的 View:
lateinit var view: View
override fun onCreate(...) {
view = findViewById(R.id.view)
}
類型推斷
可以在聲明變量時(shí)不指定變量類型其弊,自動推斷。
var name = "Daniel"
動態(tài)類型指變量的類型在運(yùn)行時(shí)可以改變膀斋,類型推斷指在代碼里不用寫變量類型梭伐,編譯器會自動推斷,Kotlin 是靜態(tài)語言仰担,不支持動態(tài)類型糊识。
var 和 val
val 是只讀變量,只能復(fù)制一次摔蓝,類似 Java 中的 final赂苗。
var 是 variable 的縮寫,val 是 value 的縮寫
可見性
Kotlin 中的變量默認(rèn)是 public 的贮尉。
函數(shù)
函數(shù)的聲明
fun cook(name: String): Food {
...
}
- 以 fun 關(guān)鍵字開頭
- 返回值寫在函數(shù)名和參數(shù)后面
- 沒有返回值對應(yīng)的類型是 Unit拌滋,并且可以省略
- 函數(shù)參數(shù)和返回值類型可以是可空類型
可見性
默認(rèn)也是 public
屬性的 getter/setter 函數(shù)
調(diào)用屬性時(shí)其實(shí)調(diào)用的是它的 getter 和 setter。
var name = "Daniel"
get() {
return field + " nb!!"
}
set(value) {
field = "good " + value
}
- getter / setter 函數(shù)有了專門的關(guān)鍵字 get 和 set
- getter / setter 函數(shù)位于 var 所聲明的變量下面
- setter 函數(shù)參數(shù)是 value
- 使用 field 表示背后的字段
- val 變量不能重寫 setter猜谚,但可以重寫 getter败砂,而且取值時(shí)還能修改
fun main() {
// 雖然 name 是 val,但這里打印的值每次都不一樣
println(Dog().name)
}
class Dog{
val name = "dog"
get() {
return field + System.currentTimeMillis()
}
}
類型
基本類型
在 Kotlin 中魏铅,所有的東西都是對象昌犹,使用的基本類型有:數(shù)字、字符览芳、布爾值斜姥、數(shù)組與字符串。
var number: Int = 1 // 還有 Double Float Long Short Byte 等
var c: Char = 'c'
var b: Boolean = true
var array: IntArray = intArrayOf(1, 2) // 還有 FloatArray DoubleArray CharArray 等
var str: String = "string"
和 Java 中的區(qū)別:
- Int 是否裝箱根據(jù)場合來定
var a:Int = 1 // unbox
var b: Int? = 2 // box
var list: List<Int> = listOf(1, 2) // box
- 數(shù)組的寫法是有區(qū)別的
var array: IntArray = intArrayOf(1, 2) // unbox
- 不可空類型沧竟、使用 IntArray铸敏、FLoatArray 等不會裝箱
- 個(gè)人理解,是否裝箱取決于背后使用的是不是對象引用以及會不會為空
類和對象
Kotlin 中的類默認(rèn)是 public 的悟泵,可以省略
類的繼承使用 : 代替 extends 或者 implement
-
構(gòu)造方法寫法不同
- Java 中會省略默認(rèn)構(gòu)造函數(shù)
- Kotlin 下面這幾種寫法都可以
// 省略構(gòu)造函數(shù)的寫法 class MainActivity : AppCompatActivity() {} // 等價(jià)的寫法 class MainActivity constructor() : AppCompatActivity() {} // 更像 Java 的寫法 class MainActivity : AppCompatActivity { constructor() { } }
- Kotlin 構(gòu)造函數(shù)使用 constructor 關(guān)鍵字
-
override 的不同
- Java 中使用 @Override 注解
- Kotlin 使用 override 關(guān)鍵字
- Kotlin 中省略了 protected 關(guān)鍵字杈笔,Kotlin 中的 override 函數(shù)的可見性是繼承自父類的
-
Kotlin 中的類默認(rèn)是 final 的,可以使用 open 關(guān)鍵字解除
- 子類不繼承 open 屬性
- 子方法會繼承 open 屬性魁袜,可以使用 final 關(guān)閉
Kotlin 中也可以用 abstract 關(guān)鍵字聲明抽象類桩撮,同 Java
Kotlin 中創(chuàng)建對象不需要 new 關(guān)鍵字
類型的判斷和強(qiáng)轉(zhuǎn)
- Kotlin 中使用 is 判斷類型,并且可以省略強(qiáng)轉(zhuǎn)
fun main() {
var activity: Activity = SubActivity()
if (activity is SubActivity) {
// 強(qiáng)轉(zhuǎn)由于類型推斷被省略了
activity.subFun()
}
}
- Kotlin 使用 as 關(guān)鍵字強(qiáng)轉(zhuǎn)(同 Java )峰弹,使用 as? 來進(jìn)行安全強(qiáng)轉(zhuǎn)
// 強(qiáng)轉(zhuǎn)
fun main() {
var activity: Activity = SubActivity()
(activity as SubActivity).subFun()
}
// 安全強(qiáng)轉(zhuǎn)
fun main() {
var activity: Activity = SubActivity()
// 注意安全強(qiáng)轉(zhuǎn)后是可空類型,需要使用 ?. 調(diào)用
(activity as? SubActivity)?.subFun()
}
思考題
- 子類重寫父類的 override 函數(shù)芜果,能否修改它的可見性鞠呈?
可以放寬,不能收窄右钾,否則多態(tài)調(diào)用的時(shí)候?qū)o法調(diào)用子方法蚁吝,同 Java旱爆。
open class Bird {
protected open fun fly(){
print("bird fly...")
}
}
class Eagle : Bird(){
// 可以
public override fun fly(){
print("eagle fly...")
}
}
class Canary : Bird(){
// 報(bào)錯(cuò)
private override fun fly(){
print("canary fly...")
}
}
- 以下的寫法有什么區(qū)別?
activity as? NewActivity
activity as NewActivity?
activity as? NewActivity?
as? 表示安全強(qiáng)轉(zhuǎn)窘茁,NewActivity? 表示轉(zhuǎn)換為可空類型怀伦,兩者并不矛盾,分情況討論山林。
activity 值 | null | NewActivity 非空實(shí)例 | 其它類型 |
---|---|---|---|
activity as? NewActivity | 不執(zhí)行 | 轉(zhuǎn)換成功 | 不執(zhí)行 |
activity as NewActivity? | 轉(zhuǎn)換結(jié)果為 null | 轉(zhuǎn)換成功 | ClassCastExecption |
activity as? NewActivity? | 轉(zhuǎn)換結(jié)果為 null | 轉(zhuǎn)換成功 | 不執(zhí)行 |
- 第一種寫法只有當(dāng) activity 為 NewActivity 非空實(shí)例時(shí)會做強(qiáng)轉(zhuǎn)房待,否則不執(zhí)行;
- 第二種寫法是不安全強(qiáng)轉(zhuǎn)驼抹,不管 activity 是什么類型桑孩,也不管是不是 null 都會強(qiáng)轉(zhuǎn),轉(zhuǎn)換失敗會拋出 ClassCastException框冀;
- 第三種寫法也是安全強(qiáng)轉(zhuǎn)流椒,如果 activity 是 NewActivity 的實(shí)例或者 null,都會安全轉(zhuǎn)換為 NewActivity? 類型明也,否則不執(zhí)行宣虾。