Kotlin抽象類與接口 (2)??接口使用

  • 接口聲明和實(shí)現(xiàn)
  • 接口與多繼承
  • 接口繼承
  • 接口中的具體函數(shù)和屬性
  • ??同一函數(shù)繼承多個(gè)實(shí)現(xiàn)的問題
  • 比抽象類更加抽象的是接口赋焕,接口包括 抽象函數(shù)和抽象屬性 渠缕,也可以根據(jù)需要有 具體的函數(shù)具體屬性(沒有‘field’)

注意:接口和抽象類都可以有抽象函數(shù)和抽象屬性抗蠢,也可以有具體函數(shù)和具體屬性举哟。那么接口和抽象類有什么區(qū)別?接口不能維護(hù)一個(gè)對(duì)象狀態(tài)迅矛,而抽象類可以妨猩,因?yàn)榫S護(hù)一個(gè)對(duì)象狀態(tài)需要支持字段,而接口中無論是具體屬性還是抽象屬性,后面都 沒有支持字段约谈。

// 抽象類
abstract class Figure {
    abstract fun onDraw()       // 抽象函數(shù)担败,無函數(shù)體
    abstract val name: String   // 抽象屬性狈网,無初始值拓哺,無getter和setter訪問器

    var cname: String = "幾何圖形"  // 具體屬性 1??
        get() = field
        set(value) {
            field = "Figure -> $value"
        }

    fun display() = println(name)  // 具體函數(shù)
}
// 接口
interface Figure {
    fun onDraw()       // 抽象函數(shù),無函數(shù)體
    val name: String   // 抽象屬性谆级,無初始值,無getter和setter訪問器

    var cname: String    // 3??具體屬性
        get() = "幾何圖形"
        set(value) {
            // 邏輯體
        }

    //var cname: String = "幾何圖形"  // 2??編譯錯(cuò)誤边锁,接口不具有支持字段 field
    //    get() = field
    //    set(value) {
    //        field = "Figure -> $value"
    //    }

    fun display() = println(name)  // 具體函數(shù)
}
  • 代碼第1??行是在抽象類中聲明了一個(gè)具體屬性 cname,且可以正常編譯通過晾蜘;

  • 代碼第2??行是在接口中聲明了一個(gè)具體屬性 cname邻眷,編譯不通過眠屎,因?yàn)闆]有 支持字段(field) 存儲(chǔ)狀態(tài)。

  • 接口中的聲明具體屬性肆饶,不能有初始值改衩,并且 gettersetter 訪問器中不能使用支持字段 field。例如上面代碼第3??行驯镊。

一葫督、接口聲明和實(shí)現(xiàn)

在 kotlin 中接口聲明使用的關(guān)鍵字是 interface。接口中可以定義 0 - N 個(gè)抽象函數(shù)和屬性板惑,也可以定義 0 - N 個(gè)具體函數(shù)和屬性橄镜。

interface 接口名 {
    fun 函數(shù)名(參數(shù)列表): 返回值類型    // 抽象函數(shù),可有可無
    var|val 屬性名: 屬性類型          // 抽象屬性冯乘,可有可無
  
    fun 函數(shù)名(參數(shù)列表): 返回值類型 {   // 具體函數(shù)洽胶,可有可無
        // 函數(shù)體
    }

    val 屬性名: 屬性類型               // 具體屬性,可有可無
        get() {
            // 不能訪問 feild
            return 具體類型實(shí)例
        }
        set(value) {
            // 邏輯體
            // 不能訪問 feild
        }
}

例如聲明一個(gè) Figure 接口的示例:

interface Figure { // 4??
    fun onDraw()       // 5??抽象函數(shù)往湿,無函數(shù)體
    val name: String   // 6??抽象屬性妖异,無初始值惋戏,無getter和setter訪問器

    val cname: String   // 7??具體屬性
        get() = "幾何圖形"

    fun display() = println(name)  // 8??具體函數(shù)
}
  • 代碼第4??行是聲明Figure接口领追,聲明接口使用 interface 關(guān)鍵字。

  • 代碼第5??行是聲明抽象函數(shù)响逢,抽象函數(shù)沒有函數(shù)體绒窑。

  • 代碼第6??行是聲明抽象屬性,抽象屬性沒有初始值舔亭,沒有 gettersetter 訪問器些膨。

  • 代碼第7??行的屬性,是具體屬性钦铺,具體屬性不能有初始值订雾,并且 gettersetter 訪問器中不能使用支持字段 field。

  • 代碼第8??行的函數(shù)矛洞,是具體函數(shù)洼哎,它有函數(shù)體。

提示:具體函數(shù)和屬性沼本,可以理解為抽象函數(shù)和屬性的默認(rèn)實(shí)現(xiàn)噩峦。

class Ellipse : Figure {

    override val name: String
        get() = "橢圓形"

    override fun onDraw() {
        println("繪制橢圓形...")
    }

    override fun display() {
        println("Ellipse -> $name")
    }
}

class Triangle(override val name: String) : Figure {

    override var cname: String
        get() = "Triangle -> $name"
        set(value) { }

    override fun onDraw() {
        println("繪制三角形...")
    }
}

class Rectangle : Figure {

    override val name: String = "矩形"

    override fun onDraw() {
        println("繪制矩形...")
    }
}

fun main(args: Array<String>) {
    val f1 = Ellipse()
    f1.onDraw()
    f1.display()
    println(f1.cname)

    val f2 = Triangle("三角形")
    f2.onDraw()
    f2.display()
    println(f2.cname)
}

2019-06-03 17:03:49.315 15906-15906/cn.ak.kot I/System.out: 繪制橢圓形...
2019-06-03 17:03:49.315 15906-15906/cn.ak.kot I/System.out: Ellipse -> 橢圓形
2019-06-03 17:03:49.316 15906-15906/cn.ak.kot I/System.out: 幾何圖形
2019-06-03 17:03:49.318 15906-15906/cn.ak.kot I/System.out: 繪制三角形...
2019-06-03 17:03:49.318 15906-15906/cn.ak.kot I/System.out: 三角形
2019-06-03 17:03:49.318 15906-15906/cn.ak.kot I/System.out: Triangle -> 三角形

注意:接口和抽象類一樣,都不能被實(shí)例化抽兆。

二识补、接口與多繼承

在 kotlin 中只允許繼承一個(gè)類,但可以實(shí)現(xiàn)多個(gè)接口辫红。通過實(shí)現(xiàn)多個(gè)接口的方法滿足多繼承的設(shè)計(jì)需求凭涂。

interface InterfaceA {
    fun methodA()
    fun methodB()
}

interface InterfaceB {
    fun methodB()
    fun methodC()
}

class AB: Any(), InterfaceA, InterfaceB {
    override fun methodA() {
        println("methodA()")
    }

    override fun methodB() { // 9??
        println("methodB()")
    }

    override fun methodC() {
        println("methodC()")
    }
}
  • 代碼第9??行是即實(shí)現(xiàn)了接口 InterfaceA 的抽象方法祝辣,也實(shí)現(xiàn)了接口 InterfaceB 的抽象方法。

三导盅、接口繼承

  • kotlin 中允許接口和接口之間繼承较幌。由于接口中的函數(shù)都是抽象函數(shù),沒有函數(shù)體白翻,所以繼承之后也不需要額外做什么乍炉。
  • 接口繼承時(shí)使用 (:) 聲明,當(dāng)繼承多個(gè)接口時(shí)使用 (,) 分隔滤馍。
interface InterfaceA {
    fun methodA()
}

interface InterfaceB {
    fun methodB()
}

interface InterfaceC : InterfaceA, InterfaceB {
    override fun methodB() // ??
    fun methodC()
}

class ABC : InterfaceC {
    override fun methodA() {
        println("methodA()")
    }

    override fun methodB() {
        println("methodB()")
    }

    override fun methodC() {
        println("methodC()")
    }
}

代碼第??行岛琼,接口 InterfaceC 中的 methodB() 重寫了接口 InterfaceB,事實(shí)上在接口中重寫抽象函數(shù)并沒有實(shí)際意義巢株,因?yàn)樗鼈兌际浅橄蟮幕比穑家艚o子類實(shí)現(xiàn)的。

四阁苞、接口中的具體函數(shù)和屬性

在 kotlin 中接口的主要成員是抽象函數(shù)和抽象屬性困檩,但是也有具體函數(shù)和具體屬性。接口中的抽象函數(shù)和抽象屬性是必須要實(shí)現(xiàn)的那槽,而具體函數(shù)和具體屬性是可選擇實(shí)現(xiàn)的悼沿。

// 定義接口InterfaceA
interface InterfaceA {
    fun methodA()
    fun methodB(): Int

    fun methodC(): String {
        return "InterfaceA -> methodC"
    }

    fun methodD(): Int = 0
}
// InterfaceA實(shí)現(xiàn)類
class InterfaceAImpl : InterfaceA {
    override fun methodA() { }

    override fun methodB(): Int {
        return 0
    }

    override fun methodC(): String {
        return "InterfaceAImpl -> methodC"
    }
}

InterfaceAImpl 必須實(shí)現(xiàn)接口 InterfaceA 中的抽象方法 methodA()methodB(),同時(shí)選擇性的重寫了接口 InterfaceA 中的具體函數(shù) methodC() 骚灸。

五糟趾、??同一函數(shù)繼承多個(gè)實(shí)現(xiàn)的問題

實(shí)現(xiàn)多個(gè)接口時(shí),可能會(huì)遇到同一函數(shù)繼承多個(gè)實(shí)現(xiàn)的問題甚牲。例如:

interface A {
    var name: String

    var age: Int

    fun foo() {
        println("A")
    }

    fun bar()
}

interface B {
    val age: Int
        get() = 15
//    val age: String     // 這種情況义郑,實(shí)現(xiàn)類C,是無法同時(shí)繼承接口A和B
//        get() = "15"

    fun foo() {
        println("B")
    }

    fun bar() {
        println("bar")
    }
}

class C : A, B {
    override var age: Int = 0

    override var name: String = "C"

    override fun foo() {
        super<A>.foo()
        super<B>.foo()
    }

    override fun bar() {
        super.bar()
    }
}

fun main(args: Array<String>) {
    val c =  C()
    println("name = ${c.name}")
    println("age = ${c.age}")
    c.foo();
    c.bar();
}

2019-06-03 18:32:34.377 24711-24711/cn.ak.kot I/System.out: name = C
2019-06-03 18:32:34.378 24711-24711/cn.ak.kot I/System.out: age = 0
2019-06-03 18:32:34.378 24711-24711/cn.ak.kot I/System.out: A
2019-06-03 18:32:34.378 24711-24711/cn.ak.kot I/System.out: B
2019-06-03 18:32:34.378 24711-24711/cn.ak.kot I/System.out: bar

當(dāng)遇到同一函數(shù)繼承多個(gè)實(shí)現(xiàn)時(shí)丈钙,子類必須重寫該函數(shù)非驮,指定具體調(diào)用哪方實(shí)現(xiàn),調(diào)用方式super<類名>.函數(shù)名()雏赦,或都不調(diào)用實(shí)現(xiàn)子類自己的函數(shù)體劫笙。屬性也是如此,但如果遇到屬性名一致但類型不一致時(shí)喉誊,實(shí)現(xiàn)類是無法同時(shí)繼承雙方接口的邀摆,如上面被注釋代碼val age: String

interface A {
    fun foo()
}

interface B {
    fun foo(): String
}

class C : A, B { // 編譯錯(cuò)誤伍茄,無法同時(shí)繼承接口A和B
    override fun foo(): String {
        return ""
    }

    override fun foo() {}
}

class D : A, B { // 編譯錯(cuò)誤栋盹,無法同時(shí)繼承接口A和B
    override fun foo(): String {
        return ""
    }
}

這種情況,接口中抽象函數(shù)名一致敷矫,返回類型不同例获,也會(huì)導(dǎo)致無法同時(shí)繼承不同接口汉额。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市榨汤,隨后出現(xiàn)的幾起案子蠕搜,更是在濱河造成了極大的恐慌,老刑警劉巖收壕,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妓灌,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蜜宪,警方通過查閱死者的電腦和手機(jī)虫埂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來圃验,“玉大人掉伏,你說我怎么就攤上這事“囊ぃ” “怎么了斧散?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)摊聋。 經(jīng)常有香客問我鸡捐,道長(zhǎng),這世上最難降的妖魔是什么栗精? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任闯参,我火速辦了婚禮瞻鹏,結(jié)果婚禮上悲立,老公的妹妹穿的比我還像新娘。我一直安慰自己新博,他們只是感情好薪夕,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赫悄,像睡著了一般原献。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上埂淮,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天姑隅,我揣著相機(jī)與錄音,去河邊找鬼倔撞。 笑死讲仰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的痪蝇。 我是一名探鬼主播鄙陡,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼冕房,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了趁矾?” 一聲冷哼從身側(cè)響起耙册,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎毫捣,沒想到半個(gè)月后详拙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蔓同,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年溪厘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牌柄。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡畸悬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出珊佣,到底是詐尸還是另有隱情蹋宦,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布咒锻,位于F島的核電站冷冗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏惑艇。R本人自食惡果不足惜蒿辙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望滨巴。 院中可真熱鬧思灌,春花似錦、人聲如沸恭取。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜈垮。三九已至耗跛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間攒发,已是汗流浹背调塌。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惠猿,地道東北人羔砾。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蜒茄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唉擂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345