初識(shí)Kotlin<下>

上一篇《初識(shí)Kotlin<上>》

在上一篇文章中介紹了Kotlin的一些基本語(yǔ)法,包括變量、常量的定義、控制循環(huán)語(yǔ)句、函數(shù)的定義及使用、類的定義、方法和屬性、繼承、數(shù)據(jù)類、枚舉類、異常處理、類型檢查和轉(zhuǎn)換等部分的內(nèi)容。這這篇文章中記錄一下接口、泛型以及擴(kuò)展的部分內(nèi)容。
接上篇繼續(xù)

8、接口:

在java語(yǔ)言中也有接口的定義,和kotlin中相比相差不大。那什么是接口呢?
接口就是對(duì)方法或者屬性的實(shí)現(xiàn)標(biāo)準(zhǔn)。這樣說(shuō)可能有點(diǎn)抽象。舉個(gè)例子:每一個(gè)自然人呢都有一個(gè)名字,然后現(xiàn)在有一個(gè)歪果仁想要加入中國(guó)的國(guó)籍,想要以后在中國(guó)發(fā)展。那咱們定義一個(gè)人(Person)的類,然后再定義一個(gè)歪果仁(ForigChinese)的類去繼承人(Person)的類。
這時(shí)候這個(gè)歪果仁要加入中國(guó)的國(guó)籍,那怎么辦呢,我們不能在Person類中添加加入中國(guó)國(guó)籍的方法。所以我們?nèi)懸粋€(gè)接口,定義一個(gè)加入中國(guó)國(guó)籍的方法,讓想要加入中國(guó)國(guó)籍的歪果仁去實(shí)現(xiàn)這個(gè)方法。這樣,這個(gè)歪果仁的實(shí)例就可以去調(diào)用加入中國(guó)國(guó)籍的方法了。
具體的咱們來(lái)看下邊的代碼:
首先定義一個(gè)Person類,因?yàn)檫@個(gè)類需要被其他的類繼承,所以使用open關(guān)鍵字來(lái)修飾

   open class Person {
        var name = ""
    }

然后去定義一個(gè)可以生存的接口:

    interface Livable {
        //接口中的屬性和方法不能初始化
        var hasSkill: Boolean//接口中的屬性
        fun addChina() //接口中的方法
        //接口中的方法可以有默認(rèn)實(shí)現(xiàn),通常指該方法是固定不變的
        fun SpeakChinese() {
            LogUtils.Loge("接口中的默認(rèn)方法:我可以說(shuō)中文")
        }
    }

然后定義一個(gè)可以在中國(guó)生存的接口:

    interface ChinaLivable {
        //接口中的屬性不可初始化
        val hasJobOffer: Boolean
        //接口中可以有g(shù)et方法,通常用于增加一個(gè)常量屬性
        val visaCatagory: String
            get() = "工作offer"
        //接口中的屬性
        var city: String
    }

然后去定義一個(gè)歪果仁的類繼承Person類,并且實(shí)現(xiàn)生存接口和在中國(guó)生存的接口:

    class ForigChinese : Person(), Livable, ChinaLivable {
        override var hasJobOffer: Boolean = true
        override var city: String = "北京"
        override var hasSkill: Boolean = true
        override fun addChina() {
            LogUtils.Loge("我叫${name}我要加入中國(guó)國(guó)籍")
        }
    }

這時(shí)候,這個(gè)歪果仁就有了生存的能力,并且有了在總過(guò)生存的能力。所以他就能加入中國(guó)國(guó)籍了。

        var mForigChinese = ForigChinese()
        mForigChinese.name = "小米"
        mForigChinese.city = "北京"
        mForigChinese.hasJobOffer = true
        mForigChinese.hasSkill = true
        mForigChinese.addChina()
        mForigChinese.SpeakChinese()
        LogUtils.Loge("接口名稱:" + mForigChinese.name)
        LogUtils.Loge("接口城市:" + mForigChinese.city)
        LogUtils.Loge("接口是否有工作:" + mForigChinese.hasJobOffer)
        LogUtils.Loge("接口是否有生存技能:" + mForigChinese.hasSkill)

然后看一下Log:

11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 我叫小米我要加入中國(guó)國(guó)籍###
11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口中的默認(rèn)方法:我可以說(shuō)中文###
11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口名稱:小米###
11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口城市:北京###
11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口是否有工作:true###
11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口是否有生存技能:true###

我們發(fā)現(xiàn)我們給歪果仁(ForigChinese )類添加了兩個(gè)能力,一個(gè)是生存的能力,一個(gè)是在中國(guó)生存的能力,但是ForigChinese類本身看起來(lái)并沒(méi)有復(fù)雜。所以,接口可以給 類附加能力,并且讓類看起來(lái)很簡(jiǎn)潔。
還有一點(diǎn),這個(gè)能力并沒(méi)有在父類中去實(shí)現(xiàn),所以通過(guò)接口的方法來(lái)實(shí)現(xiàn)某些功能,是可以選擇的,如果我不想要在中國(guó)生存的能力,就可以不實(shí)現(xiàn)這個(gè)接口就好了。使用起來(lái)很方便。

9、泛型:

泛型就是讓一個(gè)函數(shù)或者類能更加通用,首先咱們看一下系統(tǒng)給提供的一下泛型的方法。

//定義一個(gè)Int類型的數(shù)組
var intList = arrayOf(1, 2, 3, 4, 5, 6, 7, 10)
//定義一個(gè)String類型的數(shù)組
var stringList = arrayOf("1","2","3","4","5","6","7","9")

我們發(fā)現(xiàn)arrayOf方法,我們既可以傳Int類型的參數(shù)進(jìn)去,也可以傳String類型的參數(shù)進(jìn)去。這就是泛型方法的體現(xiàn)。
在我們定義方法或者類的時(shí)候,有時(shí)候也要考慮這個(gè)因素進(jìn)去,我們寫了一個(gè)工具類,能不能傳遞不同類型的傳輸進(jìn)去呢?這可以讓方法在更多的情境下使用。

9.1基本泛型

然后我們來(lái)看一下泛型在Kotlin中的寫法:

    //定義一個(gè)泛型函數(shù): <T> T表示一個(gè)占位符
    fun <T> showText(para: T) {
        LogUtils.Loge("泛型入?yún)ⅲ? + para.toString())
    }

然后調(diào)用這個(gè)方法:

 showText(3)
showText("123")

Log:

11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 泛型入?yún)ⅲ?###
11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 泛型入?yún)ⅲ?23###

我們可以看到對(duì)與一個(gè)方法showText()傳遞了兩種不同類型的參數(shù)進(jìn)去。

9.2約束泛型:

現(xiàn)在我們有一個(gè)數(shù)組

arrayOf(1, 2, 3, 4, 5, 6, 7, 10, 11)

我們相對(duì)這個(gè)數(shù)組求和,這個(gè)時(shí)候我們參數(shù)都是Int類型的,我們可以直接調(diào)用.sum()方法去求和。
然后咱們把數(shù)組改一下

arrayOf(1, 2, 3, 4, 5, 6, 7, 10, 11.11)

這樣,里邊多了一個(gè)double類型的元素。這時(shí)候就沒(méi)辦法調(diào)用.sum()方法了。然后我們使用約束泛型去實(shí)現(xiàn)一個(gè)求和方法:

 //下邊就是泛型約束:<泛型占位符: 類型>  把泛型約束在Number類型中
    fun <T : Number> sum2(vararg number: T): Double {
        return number.sumByDouble { it.toDouble() }
    }

通過(guò)上邊的注釋,大家應(yīng)該能看懂這個(gè)約束泛型的意思。就不再解釋了。

9.3多重約束泛型:

寫法就是把多個(gè)約束用where修飾,中間使用“ , ”隔開(kāi),寫在函數(shù)體之前。
例子:把數(shù)組中大于某個(gè)元素的部分都取出來(lái)并升序排列

    //Comparable 可比較的,大于、小于、等于
    fun <T> biggerPart(list: Array<T>, threhold: T): List<T>  where T : Number, T : Comparable<T> {
        return list.filter { it >= threhold }.sorted()
    }

來(lái)看一下試用方法:

//多重約束
        val biggerPart = biggerPart(arrayOf(99, 1, 2, -2, 88, 1024, 888), 3)
        for (i in biggerPart) {
            LogUtils.Loge("多重約束:${i}")
        }

Log:

11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 泛型約束:38.11###
11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 多重約束:88###
11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 多重約束:99###
11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 多重約束:888###
11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 多重約束:1024###

10、擴(kuò)展:

所謂擴(kuò)展,就是對(duì)已經(jīng)有的類,但是不能修改源碼的這種去增加一些方法。添加方法的時(shí)候要注意盡量不要和類中已經(jīng)有的方法重名,如果非要重名,那類型也不要相同。簡(jiǎn)單來(lái)說(shuō)就是別一毛一樣。舉個(gè)例子:咱們要Toast一下,但是每次寫吐司都寫的比較長(zhǎng),怎么辦呢?咱們就用這個(gè)類的擴(kuò)展,對(duì)Context類寫一個(gè)Toast擴(kuò)展:

    fun Context.ToastKotlin(message: String) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }

同樣使用也很簡(jiǎn)單(這是一個(gè)recyclerview的點(diǎn)擊事件):

        mTestAdapter!!.setOnItemClickListener(OnItemClickListener { view, position ->
            this.ToastKotlin("adapter的點(diǎn)擊事件${position}")
        })

尷尬的事情出現(xiàn)了,在Kotlin中已經(jīng)幫咱們寫了這個(gè)擴(kuò)展方法了,相信大家調(diào)用的時(shí)候會(huì)發(fā)現(xiàn)這個(gè)問(wèn)題,但是大家懂了這個(gè)意思就好了。然后咱們看一下其他的例子具體的寫法:

//擴(kuò)展函數(shù):fun 接受者類型.新擴(kuò)展函數(shù)名(參數(shù)類別){//函數(shù)實(shí)現(xiàn)}
    //1、函數(shù)擴(kuò)展
    fun Int.square(): Int {
        return this * this
    }

    //2、泛型函數(shù)擴(kuò)展:求數(shù)字型數(shù)組中的最大元素
    fun <T> Array<T>.biggest(): T
            where T : Number,
                  T : Comparable<T> {

        var biggest = this[0]
        for (t in this) {
            if (t > biggest) {
                biggest = t
            }
        }
        return biggest
    }


    //    3、屬性的擴(kuò)展(普通屬性)
    val Int.next: Int
        get() = this + 1

    //4、泛型屬性    數(shù)字類型的半徑   的面積
    val <T : Number> T.area: Double
        get() = 3.1425926 * this.toDouble() * this.toDouble()

使用:

 LogUtils.Loge("函數(shù)擴(kuò)展:" + 3.square())

        val a = arrayOf(1, 2, 3, 4, 5, 8)
        LogUtils.Loge("求最大" + a.max())
        val biggest = a.biggest()
        LogUtils.Loge("自己寫一個(gè)求最大:" + biggest)

        LogUtils.Loge("屬性擴(kuò)展:" + 3.next)
        LogUtils.Loge("屬性泛型擴(kuò)展:" + 3.area)
        LogUtils.Loge("屬性泛型擴(kuò)展:" + 'B'.toByte().area)

Log:

11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 函數(shù)擴(kuò)展:9###
11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 求最大8###
11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 自己寫一個(gè)求最大:8###
11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 屬性擴(kuò)展:4###
11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 屬性泛型擴(kuò)展:28.283333399999997###
11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 屬性泛型擴(kuò)展:13689.1333656###

這一部分,大家一看就知道具體的意思了,就不解釋了。

好啦,通過(guò)兩篇文章記錄了一下Kotlin中變量的定義、元組的使用、循環(huán)控制流的使用、類的相關(guān)使用、異常處理、接口、泛型和擴(kuò)展部分的內(nèi)容。最開(kāi)始學(xué)習(xí)Kotli就先聊這么多。我需要繼續(xù)學(xué)習(xí)了。還是上一篇中的那句話,剛開(kāi)始學(xué)習(xí)使用Kotlin,可能對(duì)概念以及用法的認(rèn)識(shí)有偏差,如有錯(cuò)誤,希望大家給予指正!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容