Kotlin學(xué)習(xí)---高階

上一節(jié)我們學(xué)習(xí)了Kotlin的一些基礎(chǔ)語(yǔ)法包括和java語(yǔ)言的一些區(qū)別,雖然說(shuō)java和kotlin是無(wú)縫對(duì)接,但是他們彼此之間相互調(diào)用還有一些需要注意的地方,

一、java與Kotlin互相調(diào)用

1、kotlin調(diào)用java時(shí),需要做非空的判斷處理,這樣避免出現(xiàn)空指針異常

2、kotlin調(diào)用java的接口,可以使用(object : javaCallback )進(jìn)行實(shí)例化后實(shí)現(xiàn)接口的方法

                                    可以直接使用({這里顯示接口方法的函數(shù)體})

                                      直接創(chuàng)建接口的的實(shí)例,并實(shí)現(xiàn)接口

3、java調(diào)用kotlin的方法,可以通過(guò)文件的名.方法名來(lái)進(jìn)行調(diào)用,但是如果不想讓java調(diào)用,可以使用雙單引號(hào)將方法名字包含起來(lái)就無(wú)法調(diào)用了

fun 'show'(){
    //此方法無(wú)法被java調(diào)用
}

4、kotlin中的擴(kuò)展函數(shù)(就是可以在任何地方為一個(gè)類擴(kuò)展一個(gè)函數(shù))

class student{
}

//此時(shí)為student添加了一個(gè)擴(kuò)展函數(shù)
fun student.add(var number:Int,var number2:Int){
}

fun main():Int{
student.add(1,2);
}

5、kotlin泛型

1)java中泛型的通配符是? 而Kotlin泛型的通配符是 *

2)kotlin 中的out 相當(dāng)于java是 extends 只讀 輸出

                in   相當(dāng)于java是 super    只寫   輸入
open class fuclass {
    var name1 = "fuclass"
}

class ziclass : fuclass() {
    var name = "ziclass"
}
fun main() {

    /**
     * TODO in out 的讀寫模式
     */
    var list: MutableList<out fuclass> = ArrayList<ziclass>()
    var temp = ziclass()
//    list.add(temp)//不能修改  報(bào)錯(cuò)
    var item1 = list.get(0)//獲取

    var list2: MutableList<in ziclass> = ArrayList<fuclass>()
//    list2.add(fuclass())
    var item = list2[0]
    println("name=${(item as ziclass).name},name1=${item.name1}")

}

3) in out 在類的聲明泛型時(shí)作用:可以控制整個(gè)類泛型讀寫模式, 而java中不能在泛型聲明的時(shí)候限定泛型的讀寫模式

  n 說(shuō)明該類的泛型只能寫     相當(dāng)于輸入,就是只寫的

  out 說(shuō)明該類的泛型只能獲取  相當(dāng)于輸出,就是只讀的

  不使用in out 說(shuō)明該類的泛型既可以輸入,也可以輸出
//在聲明泛型時(shí)候的泛型讀寫模式的限定
class Student<in T> {
    //可寫
    fun setData(data: T) {
    }
    //不可讀,報(bào)錯(cuò)
    fun getData(): T?{
        return null
    }
}

class Teacher<out T> {
    //不可寫,報(bào)錯(cuò)
//    fun setData(data: T) {
//    }

    //可讀
    fun getData(): T? {
        return null
    }
}

二、高階函數(shù)

概念:將函數(shù)作為參數(shù)傳遞給主函數(shù),該主函數(shù)稱為高階函數(shù)。

高階函數(shù)在kotlin中隨處可見(jiàn),想要深刻理解高階函數(shù),需要先來(lái)學(xué)習(xí)一下lambda表達(dá)式,這樣就讓你學(xué)起高階函數(shù)了達(dá)到事半功倍的效果。

2.1)lambda表達(dá)式

1、:() 括號(hào)中是參數(shù)

2、={} 括號(hào)中是函數(shù)體

3、var 變成val 后就不可以覆蓋了

4、只有一個(gè)參數(shù)時(shí)可以不寫(默認(rèn)是it),多個(gè)參數(shù)則需要寫清楚

//() 參數(shù)為空,返回值:Unit   函數(shù)名method , 該函數(shù)不能調(diào)用,因?yàn)闆](méi)有函數(shù)體
var method:()->Unit

//有函數(shù)體,可以調(diào)用
var method1:(Int ,Int)->Int={number1+number2=number1+number2}
method1(9,9)

var method3={number1:Int,number2:Int-> number1+number2}

//只有一個(gè)參數(shù)
var m10 : (Int) -> Unit = {
        when(it) {
            1 -> println("你是一")
            in 20..30 -> println("你是 二十 到 三十")
            else -> println("其他的數(shù)字")
        }
    }
    m10(29)

//無(wú)參數(shù)
 var m12 = { println("我就是m12函數(shù),我就是我") }
    m12()


 // 覆蓋操作
  var m14 = {number: Int -> println("我就是m14  我的值: $number")}
    m14 = {println("覆蓋  我的值: $it")}
    m14(99)

2.2)高階:

1、高階函數(shù)的最后一個(gè)參數(shù)是一個(gè)函數(shù)時(shí),在實(shí)現(xiàn)函數(shù)體時(shí) 可以在函數(shù)參數(shù)括號(hào)外使用{}來(lái)實(shí)現(xiàn)函數(shù)參數(shù)的函數(shù)體

2、使用typealias 來(lái)給高階函數(shù)起一個(gè)別名 typealias LOGIN= (String, String) -> Unit 他就像一個(gè)數(shù)據(jù)類型一樣的使用

3、當(dāng)函數(shù)參數(shù)只有一個(gè)參數(shù)時(shí),可以直接使用{}進(jìn)行閉包,默認(rèn)將一個(gè)參數(shù)命名為it,
有多個(gè)參數(shù)時(shí),無(wú)法默認(rèn) 則需要指明參數(shù)名,并用->指向函數(shù)體

4、 如果函數(shù)參數(shù)已經(jīng)有了實(shí)現(xiàn)體,那么可以通過(guò):: 來(lái)直接調(diào)用;

:: 內(nèi)部原理:就是將show_run函數(shù)的對(duì)象賦值給show_14的參數(shù),那么說(shuō)明show_run 是可以賦值給一個(gè)變量的

下面是typealias 的使用:

//類似于typedef
typealias LOGIN = (String, String) -> Unit

fun main(){
      fun loginService(username: String, password: String, login: (String, String) -> Unit) {
        login(username, password)
    }
    
    
     //高級(jí)別名的使用
    fun loginService2(username: String, password: String, login: LOGIN) {
        login(username, password)
    }
    
    //真正使用
    fun loginEngine(username: String, password: String): Unit {
        loginService(username, password) { username, pwd ->
            //此處就是高階函數(shù)的函數(shù)體
            println("username=${username},pwd=${password}")
        }
    }
     loginEngine("leon", "123456")
}

下面是一個(gè)或多個(gè)參數(shù)的使用:

fun main(){
 //  多個(gè)參數(shù)的函數(shù)參數(shù)
    fun show(mm: (String) -> Unit) {
        mm("一個(gè)參數(shù)")
    }

    show {
        println("一個(gè)參數(shù)的函數(shù)參數(shù):$it")
    }

    fun show1(mm: (String, Int) -> Unit) {
        mm("多個(gè)個(gè)參數(shù)", 1)
    }
    //下面是調(diào)用
    show1 { param1, param2 ->
        println("多個(gè)參數(shù)的函數(shù)參數(shù):param1=$param1,param2=$param2")
    }
}

下面是::來(lái)調(diào)用

fun main(){
 // :: 來(lái)調(diào)用高階的函數(shù)參數(shù)

    fun show_14(number: Int, mm: (Int) -> String): String {
        return mm(number)
    }

    fun show_run(number: Int) = "通過(guò):: 來(lái)調(diào)用函數(shù)參數(shù)的實(shí)現(xiàn)函數(shù)_$number"

    //
    val showRunObj = ::show_run
    println(show_14(50, showRunObj))
    println(show_14(100, ::show_run))
}

2.3) 高階里面的手寫標(biāo)準(zhǔn)

1、kotlin中的泛型除了數(shù)據(jù)類型,還包含了方法,方法也算一個(gè)類型,即萬(wàn)能類型

2、T 是泛型,R是返回類型的泛型

3、T.MyRun相當(dāng)于給泛型T增加了一個(gè)MyRun的擴(kuò)展函數(shù), mm: T.() -> R 代表給T增加一個(gè)匿名的擴(kuò)展函數(shù)

4、類似于RxJava中的鏈?zhǔn)秸{(diào)用

fun main(){
fun <T, R> T.MyRun(mm: () -> R): R {
        return mm()
    }

    //給T增加一個(gè)匿名函數(shù) T.()
    fun <T, R> myWith(input: T, mm: T.() -> R): R {
        return input.mm()
    }

    var age = 0
    age.MyRun {
        "headworld"
    }

    var name = "Leon"
    myWith(name) {
        length//此時(shí)可以直接獲取name的長(zhǎng)度
    }
}

2.4 高階里面的標(biāo)準(zhǔn)特色:let、apply 、also、run、with、takeIf、takeUnless、repeat

kotlin給我們提供了很多類似的標(biāo)準(zhǔn),可以參考Standard.kt里面的自己去學(xué)習(xí),

  1. let : 其實(shí)就是將調(diào)用類型的對(duì)象自己作為參數(shù)傳遞給block的函數(shù)體

  2. apply: 其實(shí)就是在執(zhí)行完block函數(shù)后,將apply的調(diào)用者返回,類似于建造者模式的鏈?zhǔn)秸{(diào)用

  3. also:將當(dāng)前調(diào)用者作為參數(shù)傳遞給block函數(shù),并將調(diào)用者作為返回值返回,便于鏈?zhǔn)秸{(diào)用

  4. run: 將調(diào)用者作為參數(shù)傳遞給block函數(shù),并將block執(zhí)行的結(jié)果返回

5)with:使用指定的receiver作為接受者調(diào)用block函數(shù)后,將block函數(shù)執(zhí)行的結(jié)果返回

6)takeIf:當(dāng)調(diào)用者滿足predicate的條件時(shí)返回調(diào)用者,不滿足時(shí)返回null

 takeUnless: 和takeIf正好相反

7)repeat: 其實(shí)就是系統(tǒng)提供出來(lái)的一個(gè)輪詢器,方便我們遍歷數(shù)組

    var Leon = "Leon"
    Leon.let {
        println("let 參數(shù)it的值是${it}")
    }

    var temp = Leon.apply {
        println("apply 回傳的this的值是$this")
    }
    println("apply 執(zhí)行后的結(jié)果$temp")

    repeat(Leon.length) {
        println("repeat輪詢:it=${it},leon的當(dāng)前位置的字符是:${Leon[it]}")
    }

//輸出的結(jié)果如下:
//let 參數(shù)it的值是Leon
//apply 回傳的this的值是Leon
//apply 執(zhí)行后的結(jié)果Leon
//repeat輪詢:it=0,leon的當(dāng)前位置的字符是:L
//repeat輪詢:it=1,leon的當(dāng)前位置的字符是:e
//repeat輪詢:it=2,leon的當(dāng)前位置的字符是:o
//repeat輪詢:it=3,leon的當(dāng)前位置的字符是:n

雖然kotlin給我們提供了很多標(biāo)準(zhǔn),其實(shí)我們還是可以自己定義我們所需要的的標(biāo)準(zhǔn)的,下面來(lái)模仿一下系統(tǒng)的repeat 做一個(gè)自定義

說(shuō)明:

1)我們?cè)谑褂孟聵?biāo)的時(shí)候,下標(biāo)從0 開始,所有這里在執(zhí)行輪詢的時(shí)候,需要使用區(qū)間,但是必須until 去掉尾部,否則會(huì)多執(zhí)行一次

2)step 后面的步長(zhǎng),必須要明確說(shuō)明,不能作為參數(shù)來(lái)進(jìn)行賦值

3)真正的操作是在action這個(gè)函數(shù)參數(shù)的函數(shù)體內(nèi)完成

 fun main(){
 
 fun doWhile(count: Int, action: (Int) -> Unit) {
        for (index in 0 until count step 1) {
            action(index)
        }
    }

    doWhile(10) {
        println("自定義輪詢器的下標(biāo):$it")
    }
}


//輸出結(jié)果如下:
自定義輪詢器的下標(biāo):0
自定義輪詢器的下標(biāo):1
自定義輪詢器的下標(biāo):2
自定義輪詢器的下標(biāo):3
自定義輪詢器的下標(biāo):4
自定義輪詢器的下標(biāo):5
自定義輪詢器的下標(biāo):6
自定義輪詢器的下標(biāo):7
自定義輪詢器的下標(biāo):8
自定義輪詢器的下標(biāo):9

2.5)自定義線程的封裝

1)我們分封裝的線程,這樣后續(xù)我們可以直接值關(guān)心耗時(shí)操作即可,

2) openThread 可以作為一個(gè)模板來(lái)使用

 fun openThread(start: Boolean, RunTask: () -> Unit): Thread? {
        val thread = object : Thread() {
            override fun run() {
                super.run()
                RunTask()
            }
        }
        return if (start) {
            thread.start()
            thread
        } else {
            null
        }
    }
    
    fun main(){
       //對(duì)比系統(tǒng)的thread代碼,大體類似

    openThread(true) {
        println("我是在子線程中執(zhí)行的耗時(shí)操作:輸出字符串")
    }
    }

今天我們主要學(xué)習(xí)了一下kotlin和java互相調(diào)用時(shí)一些需要注意的點(diǎn),著重學(xué)習(xí)了kotlin中的高階和自定義標(biāo)準(zhǔn)模板,希望對(duì)各位看官有所幫助。

?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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