Kotlin學習小記-基礎篇

2020-10-28 18:06:05

這是一份大概的kotlin學習目錄紀要,大部分內容摘自自學時的筆記。內容不夠完全,有需要詳細瞭解的地方,還需要自己單獨去查閱。主要是供給android開發人員由Java轉kotlin的碼畜們。

在這裡插入圖片描述

附上一份android進階的思維導圖,無論是學習還是鞏固,供參考。
在這裡插入圖片描述

Kotlin的介紹

在這裡插入圖片描述

注:本文為自學筆記,僅供參考,內容是自己根據自己的情況來進行標註著重點的。歡迎各位多多指教~

kotlin它是基於JVM的程式語言,它可以編譯成java位元組碼,也可以編譯成javaScript,方便在沒有JVM的裝置上執行。

關於kotlin的特點介紹如下兩點:

  1. kotlin和Java可以互調使用 讓你的專案可以根據需要,自由切換兩種語言的使用;
  2. kotlin是一門函數語言程式設計語言

入門基礎篇

屬性宣告

宣告屬性:var和val
var:可變變數;宣告的屬性可以有getter,setter方法。

var nickName:String="Max"
fun changeValue2(){
        nickName="Sherry"
}

操作:將nickeName變數從值Max修改為Sherry 結果:執行成功。

val:唯讀變數;宣告的屬性只有gette方法;類似於java中的final變數;它在建立時必須初始化,以後不可修改。

val sex:String="Female"
fun changeValue(){
        sex="Male"
}

操作:將sex唯讀變數從Female變為Male 結果:報錯Val cannot be reassigned 
結論:val是唯讀變數,賦值後不可修改

在實際開發中,定義變數的時候,你會發現,kotlin不允許未初始化的變數。如何解決?
lateinit 延遲初始化變數。值得注意的是,使用該變數的時候,要確保其不為null。

lateinit var name:String
    
    fun way(){
        print(name)
    }

引數

1.可變引數

用vararg修飾引數,kotlin的可變引數一般是函數的最後一個引數

fun <T> toList(vararg items:T):List<T>{
        val result=ArrayList<T>()
        for (item in items){
            result.add(item)
        }
        return result
 }

 fun main(arrays:Array<String>){
        val list=toList("java","kotlin","python","scala")
        println(list)
 }

在toList裡面也可以直接放入陣列。
step1:建立陣列,存入內容
step2:呼叫toList(*array)。
在stpe2裡面,引數名array前面多了一個 * 號。它表示解包陣列,能夠讓每個陣列中的每個元素在函數中被作為單獨的引數

fun main2(arrays: Array<String>){
        val array= arrayOf("java","kotlin","python","scala")
        val list=toList(*array)
        print(list)
}

2.命名引數

sum函數內有兩個引數,x=0的一個預設引數,引數y。
在呼叫函數時,命名引數則是y=1,為y指定引數的值。

fun sum(x:Int=0,y:Int):Int{
        return x+y
}

fun test(){
        sum(y=1)  //相當於 sum(0,1)
}

當y值使用預設值時:

fun sum(x:Int=0,y:Int=2,z:Int=1):Int{
        return x+y+z
    }

fun test(){
        sum(1,z=5) //類似於sum(1,2,5)
}

函數返回值

接接接下來,就是我們kotlin很重要的一個part了,什麼事孤獨終老…呸呸呸!函數的part!
在這裡插入圖片描述

1.預設返回Unit值

關於kotlin內函數的返回,它沒有java中的void,但是函數始終預設會返回一個Unit型別。

fun test1():Unit{
        println("Hello")
}

Unit返回值可以被省略:

fun test1(){
        println("Hello")
}

2.返回Nothing值情況

fun forNothing():Nothing{
        while (true){
            println("do nothing")
        }
    }

fun mainNothing(){
        forNothing()
        println("run here?")
}

結果:
do nothing
結果裡並沒有列印 run here? 所以如果返回值為 Nothing ,則Nothing表示式之後的所有程式碼都不會執行。

函數表示式

1.單表示式函數

fun sum1(x:Int=0,y:Int):Int{
        return x+y
}

當函數為單個表示式時,可以省略函數體的花括號。
等價於:

fun sum1(x:Int,y:Int):Int=x+y

也等價於:

fun sum1(x:Int,y:Int)=x+y

它根據編譯器推斷函數的返回型別。

2.成員函數

在類或物件內部定義的函數。這點和java一致。

3.區域性函數

指在一個函數中去定義另一個函數,類似於內部類。
區域性函數可以存取外部的區域性變數,甚至閉包

4.尾遞迴函數

在kotlin中實現尾遞迴的條件:
1.使用tailrec關鍵字。 使用該關鍵詞後,編譯器會優化該遞迴,從而避免堆疊溢位的問題。
2.在函數最後進行遞迴呼叫

接下來;
kotlin的類和java中的類,這東西就是,橫看成峰側成嶺,遠近高低各不同,來吧,看看是峰還是林。
在這裡插入圖片描述

1.抽象類

含有抽象方法的類,為抽象類。這一點和java的概念一致。

2.巢狀類和內部類

巢狀類:定義在某一個類內部的類。巢狀類不能存取外部類的成員,除非巢狀類變成內部類。

class OuterClass{
        val str:String="this is a outer"

        class Nested{
            fun foo()= println("")
        }
    }
    
fun main(args:Array<String>){
        OuterClass.Nested().foo()
}

內部類:

class Outter2{
        val str:String="this is property outter"
        inner class Inner{
            fun foo()= println("$str")
        }
    }

fun main(args: Array<String>){
        Outter2().Inner().foo()
}

3.列舉類

kotlin的列舉條件:enum和class關鍵字

enum class Color constructor(var colorName:String,var value:Int){
        RED("紅色",1),GREEN("綠色",2),BLUE("藍色",3)
}

列舉類的屬性不需要寫在列舉類內部,每個列舉都是列舉類的範例。

建構函式和初始化塊

kotlin的建構函式可以包括,一個主建構函式+N個次建構函式

初始化塊

init塊作為初始化塊的字首。

看到這裡是不是你有些累了?那…看一篇舔狗日記,來放鬆一下吧。繼續往下走
在這裡插入圖片描述

主建構函式

class Constructor2 constructor(){
        init {
            println("test constructor2")
        }
}

在此程式碼中,constructor作為建構函式的函數名,此時可省略函數名。

省略後的程式碼如下:

class Constructor2{
        init {
            print("test constructor2")
        }
}

+ 主建構函式可以省略constructor關鍵字,無論主構造器是否包含有引數

class Constructor2 constructor(){
        init {
            println("test constructor2")
        }

        init {
            println("test init2")
        }

        init {
            println("test init3")
        }
}

執行結果:

test constructor2
test init2
test init3

+ 初始化塊有多個,呼叫主建構函式時會按照初始化塊的順序執行。

次建構函式

+ 次建構函式,使用constructor作為函數名,但不能省略函數名。
+ 次建構函式呼叫之前必須呼叫主建構函式,次構造器函數可以包含程式碼。

   /**
     * 次建構函式
     */
    class Constructor4(str:String){
        init {
            println("$str")
        }
        
        //this(str1) 呼叫主建構函式以及它的初始化塊
        constructor(str1:String,str2:String):this (str1){
            println("$str1"+"$str2")
        }
        
        fun foo()= run { println("this is foo function!") }
    }
    
    fun mainConstructor4(args:Array<String>){
        val obj=Constructor4("testConstructor4.1","testConstructor4.2")
        obj.foo()
    }

執行結果:

testConstructor4.1
testConstructor4.1 testConstructor4.2
this is foo function

次建構函式的特點:
+ 主建構函式的屬性可以使用var,val修飾,次建構函式不能用這些修飾。
+ 次建構函式需要依託給主建構函式,呼叫次建構函式時會先呼叫主建構函式以及初始化塊。

物件宣告

在這裡插入圖片描述
Object關鍵字修飾物件:
通過物件宣告可以實現單例模式

object Singleton{
        fun printSingleton()= println("just println singleton")
}

fun main(args: Array<String>){
        println(Singleton.printSingleton())
}

將如上程式碼進行反編譯,我們可以看到物件宣告類似於 餓漢模式。

它是延遲初始化的,只有當第一次使用printSingleton()方法時,Singleton才會初始化。

物件表示式

它類似於Java中的匿名內部類。

tv_main_click.setOnClickListener(object :View.OnClickListener{
            override fun onClick(p0: View?) {
                println("print max's hello")
            }

})

它相對於java的匿名內部的特點如下:
+ 支援實現多個介面
+ 可存取非final修飾的變數

伴生物件(Companion Object)

kotlin中沒有靜態屬性和靜態方法,我們用Companion Object來解決它這一問題。簡而言之,它就是代替Java中的static。
伴生物件初始化的時間是:類載入時初始化

class PersonInfo{
        companion object{
            private var name:String="Max"
            private var age=20
            private var color="blue"
            
            fun changeLikeColor(color:String){
                this.color=color
            }

            fun printColor(){
                println("This $this.name is $this.age and she like $this.color")
            }

        }
    }

    fun main(args: Array<String>){
        PersonInfo.changeLikeColor("black")
        println(PersonInfo.printColor())

        PersonInfo.changeLikeColor("orange")
        println(PersonInfo.printColor())
    }

執行結果:

This Max is 20 and she like black
This Max is 20 and she like orange

Kotlin裡特別的類

在這裡插入圖片描述

資料類(Data class)

Data資料型別,它是由final修飾的型別,不可被繼承。

data class TestData(var name:String)
data class TestUser(var name:String,var password:String,var testData:TestData)

fun main(args: Array<String>){
        var user1=TestUser("Max","123456", TestData("TestDataUserInfo1"))

        var user2=user1.copy()
        println(user2)

        //判斷data class的copy是否為淺拷貝.若二者的address指向的記憶體地址相同,說明data的copy為淺拷貝,否則為深拷貝。
        println(user2.testData===user1.testData)

        var user3=user1.copy("Caroline")
        println(user3)

        var user4=user1.copy(password = "asdfgh")
        println(user4)
    }

執行結果為:

true
TestUser(name=Caroline, password=123456, testData=TestData(testData=TestDataUserInfo1))
TestUser(name=Frank, password=asdfgh, testData=TestData(testData=TestDataUserInfo1))

tips:===比較的是記憶體地址

密封類(Sealed class)

密封類一般和when語句搭配使用,從功能上而言,更類似於列舉。

sealed class Normal(val name:String)

class Dog(dogName:String):Normal(dogName)
class Cat(catName:String):Normal(catName)
class Deer(deerName:String,val color:String):Normal(deerName)

fun greetNormal(normal:Normal)= when (normal){
    is Dog->"print ${normal.name}"
    is Cat->"print ${normal.name}"
    is Deer->"print ${normal.name} the color is ${normal.color}"
}

fun main(array: Array<String>){
    println(greetNormal(Dog("發財")))
    println(greetNormal(Cat("恭喜")))
    println(greetNormal(Deer("flash","yellow")))
}

執行結果:

print 發財
print 恭喜
print flash the color is yellow

密封類特點:
密封類是一個抽象類
密封類的所有子類要麼在密封類中,要麼跟密封類在同一檔案中,密封類的子類的子類,可在任意位置。
若和when語句聯合使用時,is語句可涵蓋所有的情況,則無需新增else語句。

以上的內容為kotlin很基礎的入門篇,對我來說,很重要的就是對於函數的使用部分,物件宣告對於單例模式的實現的理解使用。
後續若有新知識get到,那就隨緣更新吧。
在這裡插入圖片描述