Kotlin實戰指南五:繼承、接口

轉載請標明出處:https://blog.csdn.net/zhaoyanjun6/article/details/87874895
本文出自【趙彥軍的博客】


繼承

在 Kotlin 中所有類都有一個共同的超類 Any,這對於沒有超類型聲明的類是默認超類:

class Example // 從 Any 隱式繼承

Any 默認提供了三個函數:

equals()
hashCode()
toString()

子類有主構造函數

如果一個類要被繼承,可以使用 open 關鍵字進行修飾。

open class User(var age:Int)

class Student(age: Int) : User(age)

代碼調用

 var student = Student(100)
 Log.e("zhaoyanjun:", ""+ student.age ) //輸出結果

子類沒有主構造函數

如果子類沒有主構造函數,則必須在每一個二級構造函數中用 super 關鍵字初始化基類,或者在代理另一個構造函數。初始化基類時,可以調用基類的不同構造方法。

open class User(var age: Int)

class Student : User{
     constructor(age: Int):super(age)
}

子類重寫父類的方法

如果父類的方法可以被子類重寫,可以使用 open 關鍵字進行修飾。

open class User(var age: Int){
   
   //能夠被覆蓋 
   open fun run(){}
   
   //不能被覆蓋 
   fun run2(){}
}


class Student : User{

    constructor(age: Int):super(age)

    //子類重寫父類的方法
    override fun run() {
        super.run()
    }
}

屬性重寫

如果父類允許某個屬性能夠被重寫,需要用 open 字段修飾。子類需要的屬性需要用 override 字段修飾。

子類可以用 var 來重寫父類 val , 反之則不行。因爲一個 val 屬性本質上聲明瞭一個 getter 方法,而將其覆蓋爲 var 只是在子類中額外聲明一個 setter 方法。

open class User(var age: Int) {
   //允許子類重寫,用 open 修飾
    open val name: String? = null
}

class Student : User {
   //重寫父類的屬性,用 override 修飾
    override var name:String?=null

    constructor(age: Int) : super(age)
}

接口

Kotlin 的接口與 Java 8 類似,既包含抽象方法的聲明,也包含實現。與抽象類不同的是,接口無法保存狀態。它可以有屬性但必須聲明爲抽象或提供訪問器實現。

使用關鍵字 interface 來定義接口

interface MyInterface {
    fun bar()
    fun foo() {
      // 可選的方法體
    }
}

實現接口

一個類或者對象可以實現一個或多個接口。

class Child : MyInterface {
    override fun bar() {
        // 方法體
    }
}

接口中的屬性

你可以在接口中定義屬性。在接口中聲明的屬性要麼是抽象的,要麼提供訪問器的實現。在接口中聲明的屬性不能有幕後字段(backing field),因此接口中聲明的訪問器不能引用它們。

interface MyInterface {
    val prop: Int // 抽象的

    val propertyWithImplementation: String
        get() = "foo"

    fun foo() {
        print(prop)
    }
}

class Child : MyInterface {
    override val prop: Int = 29
}

接口繼承

一個接口可以從其他接口派生,從而既提供基類型成員的實現也聲明新的函數與屬性。很自然地,實現這樣接口的類只需定義所缺少的實現:

interface Named {
    val name: String
}

interface Person : Named {
    val firstName: String
    val lastName: String
    
    override val name: String get() = "$firstName $lastName"
}

data class Employee(
    // 不必實現“name”
    override val firstName: String,
    override val lastName: String,
    val position: Position
) : Person

解決覆蓋衝突

實現多個接口時,可能會遇到同一方法繼承多個實現的問題。例如

interface A {
    fun foo() { print("A") }
    fun bar()
}

interface B {
    fun foo() { print("B") }
    fun bar() { print("bar") }
}

class C : A {
    override fun bar() { print("bar") }
}

class D : A, B {
    override fun foo() {
        super<A>.foo()
        super<B>.foo()
    }

    override fun bar() {
        super<B>.bar()
    }
}

上例中,接口 A 和 B 都定義了方法 foo() 和 bar()。 兩者都實現了 foo(), 但是隻有 B 實現了 bar() (bar() 在 A 中沒有標記爲抽象, 因爲沒有方法體時默認爲抽象)。因爲 C 是一個實現了 A 的具體類,所以必須要重寫 bar() 並實現這個抽象方法。

然而,如果我們從 A 和 B 派生 D,我們需要實現我們從多個接口繼承的所有方法,並指明 D 應該如何實現它們。這一規則既適用於繼承單個實現(bar())的方法也適用於繼承多個實現(foo())的方法。


個人微信號:zhaoyanjun125 , 歡迎關注

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章