Kotlin學(xué)習(xí)筆記(二)-程序結(jié)構(gòu)(上 )

[TOC]

前言

上節(jié)我們主要講了Kotlin的數(shù)據(jù)類型,這節(jié)我們主要從程序結(jié)構(gòu),包括方法,類成員,運算符的角度去認(rèn)識Kotlin

常量與變量

上一節(jié)我們已經(jīng)用到了用val,var來修飾屬性。這節(jié)我們詳細(xì)總結(jié)下:

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

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

Java:

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

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

Kotlin:

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

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

    • var = variable
    • var x ="HelloWorld"http://定義變量
    • x ="HiWorl"http://再次賦值
  • 類型推導(dǎo)
    編譯器可以推導(dǎo)量的類型

    • val string =“Hello"http://推導(dǎo)出String類型
    • valint=5IIInt類型
    • var x = getString() + 5 //String類型
函數(shù)

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

舉例:

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

Java是面向?qū)ο蟮?,Kotlin是面向函數(shù)的,函數(shù)是一等公民,是在Java中你可以將調(diào)用一個對象,也可以將一個對象傳來傳去,在Kotlin中函數(shù)也是可以的做到像Java對象一樣,下面結(jié)合代碼來體驗一下

fun main(args: Array<String>) {
    
    //不建議這么去寫  這么寫 是無法區(qū)分你想調(diào)用的是常量還是函數(shù)
    //這里和重載也不相同 因為val sum =fun 后面接的是無方法名的方法
    //這里默認(rèn)是調(diào)用的方法  如果想調(diào)用常量方法  可以使用sum.invoke()等價于 sum()
    println("方法函數(shù) " + sum(args[0].toInt(), args[1].toInt()))
    println("方法函數(shù) 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 "請輸入兩個數(shù)值 例: 1 2"
}

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

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

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

  • lambda表達式的重要特征

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

簡單例子:

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

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

這里我再結(jié)合前面講的函數(shù)和Kotlin特性寫幾個例子:

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

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

val multiply_3 = { arg1: Int, arg2: Int -> arg1 * arg2 }//匿名函數(shù) 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
}//匿名函數(shù) Lambda: (Int,Int)->Int
val multiply_6 = {//匿名函數(shù) Lambda: ()->Unit
    //lambda
    println("HelloWorld")
}

fun printlnUsage() {//具名函數(shù) Lambda: ()->Unit
    println("no return element")
}
//匿名函數(shù) Lambda: ()->Unit
val sum1 = { it: String ->
    println(it)//方法體內(nèi)容
    Unit//最后一行作為lambda的返回值 Kotlin Unit相當(dāng)于Java的Void無返回值
}

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

  • 循環(huán)語句
    Kotlin的循環(huán)語句有些特殊看下面的例子:
//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")
}

當(dāng)調(diào)用第二種循環(huán),如果如上想跳出循環(huán),那么println("The End")這句并不會執(zhí)行。因為 {}中的內(nèi)容是表達式而不是函數(shù),所以return的是main這個函數(shù),可以改成如下:

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

    }
    println("The End")

添加標(biāo)識,return@Continue相當(dāng)于java的Continuereturn@Break相當(dāng)于Java的break。(這里標(biāo)識的定義是隨便寫的,@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//默認(rèn)可以不寫
        set(value) {//默認(rèn)可以不寫
            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
}

我們直接對上面的代碼進行總結(jié):

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

結(jié)語

篇幅不宜過長,下篇繼續(xù)說說程序結(jié)構(gòu)

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

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

相關(guān)閱讀更多精彩內(nèi)容

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