Kotlin知識(shí)歸納(一) —— 基礎(chǔ)語(yǔ)法

前序

????????在19年的Google I/O大會(huì)上,Kotlin 成為 Android 開(kāi)發(fā)首選語(yǔ)言。而著名的OkHttp 已經(jīng)開(kāi)始用 Kotlin 進(jìn)行重寫(xiě)工作。是時(shí)候通過(guò)寫(xiě)博客歸納來(lái)鞏固Kotlin基礎(chǔ)知識(shí)。

(一)、語(yǔ)法上的變更

  • 創(chuàng)建對(duì)象不需要new關(guān)鍵字
  • 語(yǔ)句不需要;結(jié)尾,加;也無(wú)所謂
  • 變量類型后置,即變量名在前,變量類型在后。例如 str:String
  • 使用 println() 替代 System.out.println()

(二)、定義變量

????????Kotlin中使用val關(guān)鍵字聲明常量(即變量初始化之后不可再次賦值),var關(guān)鍵字聲明變量。

變量定義時(shí)可以不顯示指定類型,編譯器會(huì)根據(jù)其初始化器的類型進(jìn)行推斷。

//自動(dòng)推斷出 `Int` 類型
var daqi = 1
//可以顯式地指定變量的類型
val a :String = "daqi"
//如果變量沒(méi)有初始化器,需要顯式地指定它的類型
val c: Int
c = 3  

當(dāng)編譯器能確保val變量只有唯一一條初始化語(yǔ)句會(huì)被執(zhí)行,可以根據(jù)條件對(duì)它初始化不同的值。

val daqi:String
var isChange = true
if (isChange){
   daqi = "1"
}else{
   daqi = "2"
}

val變量的引用自身是不可變的,但是它指向的對(duì)象是可變的。

val languages = arrayListOf("Java")
languages.add("Kotlin")

var 關(guān)鍵字允許變量改變自己的值,但不能改變自己的類型。

var daqi = 1
//編譯不通過(guò)
daqi = ""

(三)、定義函數(shù)
Kotlin 中使用 fun 關(guān)鍵字聲明函數(shù)。
完整的函數(shù)定義:

修飾符(默認(rèn)public)+ fun + 方法名 + (參數(shù)列表) :返回值 {
        函數(shù)體
}
image
public fun daqi(name:String):String {
}

表達(dá)式函數(shù)體

????????當(dāng)單個(gè)表達(dá)式構(gòu)成完整的函數(shù)體時(shí),可以直接去掉 {} 和 return 語(yǔ)句,函數(shù)的返回值類型編譯器也會(huì)自動(dòng)推斷。這種函數(shù)就是表達(dá)式函數(shù)。

fun sum(a: Int, b: Int) = a + b

語(yǔ)句和表達(dá)式的區(qū)別在于:

  • 表達(dá)式有值,并且能作為另一個(gè)表達(dá)式的一部分使用;
  • 語(yǔ)句總是包圍著它的代碼塊中的頂層元素,并且沒(méi)有自己的值。

????????在 Java 中,所有的控制結(jié)構(gòu)都是語(yǔ)句。而在 Kotlin 中,除了循環(huán)( for, do 和 do/while )以外大多數(shù)控制結(jié)構(gòu)都是表達(dá)式(例如:if、 when 以及 try 屬于表達(dá)式)

???????? 表達(dá)式函數(shù)不光用在些簡(jiǎn)單的單行函數(shù)中 ,也可以用在對(duì)更復(fù)雜的單個(gè)表達(dá)式求值的函數(shù)中。

fun max(a: Int, b: Int ) = if (a > b) a else b

無(wú)返回值的函數(shù)

類似Java的返回值類型為void的函數(shù)

fun daqi():Unit{
}

可省略Unit類型

fun daqi(){
}

(三)、字符串模板

在 Java 中,當(dāng)需要打印變量描述和其值時(shí),往往如下打?。?/p>

String str = "daqi";
System.out.println("str = " + str);

????Kotlin支持字符串模板,可以在字符串中引用局部變量,但需要在變量名前加上$。表達(dá)式會(huì)進(jìn)行靜態(tài)檢查, 如果$引用一個(gè)不存在的變量,代碼不會(huì)編譯通過(guò)。

val str = "daqi"
printlin("str = $str")

$不僅限于引用于簡(jiǎn)單的變量名稱,還可以引用更復(fù)雜的表達(dá)式。

val daqi = intArrayOf(1,2,3)
println("${daqi[0]}")

在$引用的表達(dá)式內(nèi)(即花括號(hào){}中)可以直接嵌套雙引號(hào)

println("daqi的第一個(gè)元素: ${if(daqi.size > 0) daqi[0] else "null"}")

當(dāng)需要打印$符號(hào)時(shí),可以對(duì)其進(jìn)行轉(zhuǎn)義,或者利用表達(dá)式對(duì)其進(jìn)行打?。?/p>

//打印結(jié)果為:$str
val str = "daqi"
println("\$str")
println(${'$'}daqi)

(四)、類和屬性

在java中定義一個(gè)簡(jiǎn)單類:

public class Person{
    private final String name;
    
    public Person(String name){
        this.name = name;
    }
    
    public String getName(){
        return name;
    }
}

用Kotlin寫(xiě)的Person類(默認(rèn)public修飾)

class Person(val name:String)

延伸:若想知道Kotlin對(duì)應(yīng)的具體Java實(shí)現(xiàn),可以通過(guò)idea的工具,對(duì)Kotlin文件進(jìn)行反編譯:

????Tools ->Kotlin -> Show Kotlin Bytecode -> 右側(cè)彈出字節(jié)碼框 ->左上角 Decompile按鈕

image
image

整體基本和Java類相似,但是該類被定義為final類,即太監(jiān)類,不可被繼承。

setter 和 getter

????在Kotlin中,當(dāng)你聲明屬性的時(shí)候,也就聲明了對(duì)應(yīng)的訪問(wèn)器(即get和set)

????val屬性只有一個(gè)getter,var屬性既有 getter 和 setter。
聲明一個(gè)屬性的完整語(yǔ)法:

var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]

????其中,初始化器,getter 和 setter 都是可選的。如果類型可以從初始化器或者getter 返回值中推斷出來(lái),也可以省略。
訪問(wèn)器的默認(rèn)實(shí)現(xiàn)非常簡(jiǎn)單,即對(duì)對(duì)應(yīng)變量的返回和更改。

當(dāng)需要在值被訪問(wèn)或修改時(shí)提供額外的邏輯,可以通過(guò)自定義getter和setter

自定義getter

在Kotlin中的實(shí)現(xiàn)

class Rectangle(val height:Int,val width:Int){
    val isSquare:Boolean
        get(){
            return height == width
        }
}

對(duì)應(yīng)的Java實(shí)現(xiàn):

image

自定義setter

在Kotlin中實(shí)現(xiàn):

class Rectangle(val height:Int,val width:Int){
    var isSquare:Boolean = false
        set(value) {
            field = value
        }
}

在setter方法中,使用特殊的標(biāo)識(shí)符field來(lái)訪問(wèn)支持字段(幕后字段)的值。具體幕后字段后面再說(shuō)。

注意:

????Kolin中,名稱以is開(kāi)頭的變量。轉(zhuǎn)換成對(duì)應(yīng)的Java get 和 set 方法時(shí),getter不會(huì)添加任何的前準(zhǔn),setter名稱中的is會(huì)被替換成set。

class Person(
    var isDaqi:Boolean = false
)

該對(duì)象在Java中的訪問(wèn)器為:

image

(五)、迭代

Kotlin中 while 和 do-while循環(huán),其語(yǔ)法與Java的基本沒(méi)區(qū)別。

而for循環(huán)僅以一種形式存在,和for-each差不多。但用 in 取代了 :

fun iterationArray(args:Array<String>){
    for (str in args) {

    }
}

????for循環(huán)還可以遍歷區(qū)間。區(qū)間本質(zhì)上是兩個(gè)值之間的間隔。使用..運(yùn)算符表示區(qū)間。

????Kotlin中的區(qū)間是閉合區(qū)間,即結(jié)束值也是區(qū)間的一部分。而區(qū)間默認(rèn)迭代步長(zhǎng)為1。

val oneToTen = 1..10

????可以通過(guò)step關(guān)鍵字修改步長(zhǎng)。遍歷時(shí),i變量其增長(zhǎng)幅度將變?yōu)?,即每次迭代時(shí)都會(huì)自增2。

for(i in 0..100 step 2){
}

如果想要一個(gè)半閉合區(qū)間,即結(jié)束值不屬于區(qū)間的一部分,可以使用until關(guān)鍵字,

val oneToNine = 1 until 10

如果需要一個(gè)倒序的區(qū)間,可以使用downTo關(guān)鍵字

val tenToOne = 10 downTo 1

此時(shí),將從10一直遞減到1進(jìn)行循環(huán)。downTo表示的區(qū)間也是一個(gè)閉合區(qū)間。

如果想實(shí)現(xiàn)普通for循環(huán)一樣,對(duì)數(shù)據(jù)索引進(jìn)行循環(huán),可以使用數(shù)組的indices變量

for (i in args.indices) {
    println(args[i])
}

(六)、if表達(dá)式

在Kotlin中,if是一個(gè)表達(dá)式,即它會(huì)返回一個(gè)值。

if的分支為代碼塊時(shí),最后的表達(dá)式將作為該代碼塊的值:

val max = if (a > b) {
    print("Choose a")
    a
} else {
    print("Choose b")
    b
}

(七)、when表達(dá)式

Kotlin中的when,對(duì)應(yīng)的是Java中的switch,但比起更加強(qiáng)大。

????when 將它的參數(shù)與所有的分支條件按順序比較,直到某個(gè)分支滿足條件,執(zhí)行其分支對(duì)應(yīng)的代碼。當(dāng)多分支需要用相同的方式處理時(shí),可以把其放在一起,用逗號(hào)分隔。

????當(dāng)when作為表達(dá)式使用時(shí),必須有 else 分支, 除非編譯器檢測(cè)出所有的可能情況都已經(jīng)被覆蓋。(例如枚舉類)

when (x) {
    0, 1 -> print("x == 0 or x == 1")
       2 -> print("x == 2")
    else -> print("otherwise")
}

有沒(méi)有發(fā)現(xiàn),沒(méi)有了那繁瑣的case和break!!

????when的參數(shù)可有可無(wú),并且無(wú)限制類型!而且可以用任意表達(dá)式作為分支條件。(switch要求必須使用常量作為分支條件~)

????when作為表達(dá)式函數(shù)的的函數(shù)體,直接使用函數(shù)的參數(shù),自身并無(wú)設(shè)置參數(shù)。并在條件語(yǔ)句中使用in或者!in 判斷一個(gè)變量是否在區(qū)間或者集合中。

fun daqi(num:Int,intArray: IntArray) = when{
    num in 1..10 -> "1~10"
    num !in intArray -> "no in Array"
    else -> "other"
}

when 也可以用來(lái)取代 if-else if鏈.

fun daqi(num:Int) = when{
    num < 0 -> "小于0"
    num >0 && num < 10 -> "1..10"
    else -> "other"
}

????is可以檢查一個(gè)變量是否是某種類型,再配合智能轉(zhuǎn)換(檢查過(guò)某個(gè)變量的類型后,不再需要再轉(zhuǎn)換它,直接可以把它當(dāng)作檢查過(guò)的類型使用)可以很方便的對(duì)進(jìn)行類型安全操作。

//Any類似于Java的Object
fun daqi(num:Any) = when(num){
    is String -> {
        //此時(shí)num已經(jīng)為String類型
        println("該變量類型為String,獲取其長(zhǎng)度")
        println(num.length)
    }
    is Int -> {
        //此時(shí)num已經(jīng)為Int類型
        println("該變量類型為Int,將其與10進(jìn)行對(duì)比")
            num.rangeTo(10)
    }
    else -> "other"
}

(八)、Kotlin中的異常

????Kotlin的異常處理與Java類似。當(dāng)拋出異常時(shí),不需要使用new關(guān)鍵字創(chuàng)建異常實(shí)例。

var daqi:String? = null
if (daqi == null){
    throw NullPointerException("daqi is null")
}

????try也可以作為表達(dá)式,將其賦值給變量。當(dāng)代碼執(zhí)行正常,則try代碼塊中最后一個(gè)表達(dá)式作為結(jié)果,如果捕獲到異常,對(duì)應(yīng)catch代碼塊中最后一個(gè)表達(dá)式作為結(jié)果。finally 塊中的內(nèi)容不會(huì)影響表達(dá)式的結(jié)果。

fun readNumber(reader:BufferedReader):Int? = try{
    Integer.parseInt(reader.readLine())
}catch(e:NumberFormatException){
    null
}catch (e:NullPointerException){
    null
}finally {
    reader.close()
}

可以有0到多個(gè) catch 塊。finally 塊可以省略。 但是 catch 與 finally 塊至少應(yīng)該存在一個(gè)。

(九)、枚舉

????kotlin中用兩個(gè)關(guān)鍵字enum和class聲明枚舉類。enum是一個(gè)軟關(guān)鍵字,只有當(dāng)它出現(xiàn)在class前面時(shí)才有特殊的意義。

聲明普通枚舉類:

enum class Color{
    RED,BLUE
}

聲明帶屬性的枚舉類:

enum class Color(val r:Int,val g:Int,val b:Int){
    RED(255,0,0),BLUE(0,0,255);
    fun rgb = (r * 256 + g) * 256 + b
}

如果在枚舉類型中定義任何方法,需要使用分號(hào);把枚舉常量列表和方法定義分開(kāi)。

參考文獻(xiàn):

android Kotlin系列:

Kotlin知識(shí)歸納(一) —— 基礎(chǔ)語(yǔ)法

Kotlin知識(shí)歸納(二) —— 讓函數(shù)更好調(diào)用

Kotlin知識(shí)歸納(三) —— 頂層成員與擴(kuò)展

Kotlin知識(shí)歸納(四) —— 接口和類

Kotlin知識(shí)歸納(五) —— Lambda

Kotlin知識(shí)歸納(六) —— 類型系統(tǒng)

Kotlin知識(shí)歸納(七) —— 集合

Kotlin知識(shí)歸納(八) —— 序列

Kotlin知識(shí)歸納(九) —— 約定

Kotlin知識(shí)歸納(十) —— 委托

Kotlin知識(shí)歸納(十一) —— 高階函數(shù)

Kotlin知識(shí)歸納(十二) —— 泛型

Kotlin知識(shí)歸納(十三) —— 注解

Kotlin知識(shí)歸納(十四) —— 反射

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容