一天入門Kotlin學習筆記(二)-程序結構(上 )

前言

上節我們主要講了Kotlin的數據類型,這節我們主要從程序結構,包括方法,類成員,運算符的角度去認識Kotlin

常量與變量

上一節我們已經用到了用val,var來修飾屬性。這節我們詳細總結下:

  • 常量(val)
    • val=value,值類型
    • 類似Java的final
    • 不可能重複賦值
    • 運行時常量: val x = getX()
    • 編譯期常量: const val x=2

Java final是運行時常量 Kotlin是編譯器常量 例子:

Java:

public final String S1="A"
public String s2=S1

運行時字節碼: 
public s2="A" //直接指向值 而不是變量名  

Kotlin:

val S1:String="A"
var s2:String =S1

運行時字節碼: 
static{
    s2=S1//這裏沒有直接指向S1的值 所以是編譯期常量
}
  • 變量(var)

    • var = variable
    • var x =“HelloWorld”//定義變量
    • x =“HiWorl”//再次賦值
  • 類型推導
    編譯器可以推導量的類型

    • val string =“Hello"//推導出String類型
    • valint=5IIInt類型
    • var x = getString() + 5 //String類型
函數

函數是以特定功能組織起來的代碼塊

舉例:

  • fun sayHi(name: String){ println(“Hi, $name”) }
  • fun sayHi(name: String) = println(“Hi, $name")
  • 匿名函數
    • fun([參數列表])): [返回值類型]{ [函數體] }
      • 舉例:- val sayHi = fun(name: String) = println(“Hi, $name")

Java是面向對象的,Kotlin是面向函數的,函數是一等公民,是在Java中你可以將調用一個對象,也可以將一個對象傳來傳去,在Kotlin中函數也是可以的做到像Java對象一樣,下面結合代碼來體驗一下

fun main(args: Array<String>) {
    
    //不建議這麼去寫  這麼寫 是無法區分你想調用的是常量還是函數
    //這裏和重載也不相同 因爲val sum =fun 後面接的是無方法名的方法
    //這裏默認是調用的方法  如果想調用常量方法  可以使用sum.invoke()等價於 sum()
    println("方法函數 " + sum(args[0].toInt(), args[1].toInt()))
    println("方法函數 invoke: " + sum(args[0].toInt(), args[1].toInt()))
    println("常量" + sum.invoke(args[0].toInt(), args[1].toInt()))

}
fun sum(aInt1: Int, aInt2: Int): Int {
    return aInt1 + aInt2
}

val sum = fun(aInt1: Int, aInt2: Int): Int {
    println("$aInt1 + $aInt2 = ${sum(aInt1, aInt2)}")
    return aInt1 + aInt2
}
fun printlnUarge(): String {
    return "請輸入兩個數值 例: 1 2"
}

val uager = fun(): String {
    return "請輸入兩個數值 例: 1 2"
}
Lambda表達式

Lambda 允許把函數作爲一個方法的參數(函數作爲參數傳遞進方法中)。
使用 Lambda 表達式可以使代碼變的更加簡潔緊湊。
Java1.8加入,Kotlin作爲面向函數編程的語言,他一出生就完美支持lambda

  • 語法
(parameters) -> expression
或
(parameters) ->{ statements; }

  • lambda表達式的重要特徵

    • 可選類型聲明:不需要聲明參數類型,編譯器可以統一識別參數值。
    • 可選的參數圓括號:一個參數無需定義圓括號,但多個參數需要定義圓括號。
    • 可選的大括號:如果主體包含了一個語句,就不需要使用大括號。
    • 可選的返回關鍵字:如果主體只有一個表達式返回值則編譯器會自動返回值,大括號需要指定明表達式返回了一個數值。

簡單例子:

// 1. 不需要參數,返回值爲 5  
() -> 5  
  
// 2. 接收一個參數(數字類型),返回其2倍的值  
x -> 2 * x  
  
// 3. 接受2個參數(數字),並返回他們的差值  
(x, y) -> x – y  
  
// 4. 接收2個int型整數,返回他們的和  
(int x, int y) -> x + y  
  
// 5. 接受一個 string 對象,並在控制檯打印,不返回任何值(看起來像是返回void在Kotlin中時Unit)  
(String s) -> System.out.print(s)

Lambda表達式要是細說的話可能一篇文章也不夠,我覺得剛開始看雖然代碼變的更簡潔,但是對我我這種只會Java一種語言的來說一下子轉變有時候還是挺彆扭的,感覺這個就得多寫多看慢慢適應。

這裏我再結合前面講的函數和Kotlin特性寫幾個例子:

fun multiply_1(arg1: Int, arg2: Int): Int {//具名函數 Lambda: (Int,Int)->Int
    return arg1 * arg2
}

fun multiply_2(arg1: Int, arg2: Int) = arg1 * arg2//具名函數 Lambda: (Int,Int)->Int

val multiply_3 = { arg1: Int, arg2: Int -> arg1 * arg2 }//匿名函數 Lambda: (Int,Int)->Int


val multiply_4 = { arg1: Int, arg2: Int ->
    //lambda
    println("HelloWorld multiply_4")
    println("HelloWorld multiply_4")
    println("HelloWorld multiply_4")
    arg1 * arg2//最後一行作爲lambda的返回值

}
val multiply_5 = fun(arg1: Int, arg2: Int): Int {
    return arg1 * arg2
}//匿名函數 Lambda: (Int,Int)->Int
val multiply_6 = {//匿名函數 Lambda: ()->Unit
    //lambda
    println("HelloWorld")
}

fun printlnUsage() {//具名函數 Lambda: ()->Unit
    println("no return element")
}
//匿名函數 Lambda: ()->Unit
val sum1 = { it: String ->
    println(it)//方法體內容
    Unit//最後一行作爲lambda的返回值 Kotlin Unit相當於Java的Void無返回值
}

這幾個例子應該覆蓋了我們會用到的大部分例子的類比了。

  • 循環語句
    Kotlin的循環語句有些特殊看下面的例子:
//args=a b c d e f
fun main(args: Array<String>) {

    for (i in args) {
        println(i)
    }
    args.forEach{
        if (it == "d") return
        println(it)
    }
    println("The End")
}

當調用第二種循環,如果如上想跳出循環,那麼println(“The End”)這句並不會執行。因爲 {}中的內容是表達式而不是函數,所以return的是main這個函數,可以改成如下:

    run Break@/*外部標識*/{
        args.forEach Continue@/*內部標識*/{
            if (it == "d") return@Continue
            println(it)
        }

    }
    println("The End")

添加標識,return@Continue相當於java的Continuereturn@Break相當於Java的break。(這裏標識的定義是隨便寫的,@A @ABC都可以)

成員方法和成員變量

這部分比較簡單直接舉例子:

class X
class B {
//    lateinit var a:Int //錯誤 不能再原始類型中使用 lateinit
//    lateinit var a:Double//error
//    lateinit var a1:Long//error
//    lateinit var a2:Float//error
//    lateinit var a3:Short//error
//    lateinit var a4:Char//error
//    lateinit var a5:Byte//error
//    lateinit var b: Boolean//error
    var a: Int = 0
        get() = field//默認可以不寫
        set(value) {//默認可以不寫
            field = value
        }
    lateinit var c: String

    lateinit var x1: X
    //    lateinit  val x2: //錯誤  不可以 val 類似final 定義後別虛初始化
    val x2: X by lazy {
        X()
    }
    var cc: String? = null

    fun value() {

    }
}

fun main(args: Array<String>) {

    val b = B()
    b.value()
    b.a
}

我們直接對上面的代碼進行總結:

  • var/val a: Int = 0默認訪問修飾符是public,同時默認幫我們getter和setter,當然我們也可以重寫這兩個方法
  • field這個屬性(也叫Backing Field)只能在getter和setter才能訪問到,更多詳見理解Backing Field
  • Kotlin建議val/var修飾的屬性最好直接初始化或是在構造方法中初始化,如果不可以就降級爲局部變量**
  • lateinit延時初始化,不可以修飾val不可以修飾基本數據類型(因爲基本數據類型有默認值),理智使用lateinit否則會空指針
  • by lazy{} 可以修飾val

結語

篇幅不宜過長,下篇繼續說說程序結構

Github源碼直接運行,包含全部詳細筆記

發佈了33 篇原創文章 · 獲贊 8 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章