Kotlin繼承


繼承是物件導向程式設計語言的一個重要特徵。 繼承允許將類(或基礎類別或父類別)的特性繼承到新類(或派生類或子類)。

主類稱為超類(或父類別),繼承超類的類稱為子類(或子類)。 子類包含超類的特性以及它自己的特性。

當兩個或多個類具有相同的屬性時,這就引入繼承的概念。 繼承用於提高程式碼可重用性。 派生類只有一個基礎類別,但可以有多個介面,而基礎類別可能有一個或多個派生類。

在Kotlin中,派生類在類頭中使用冒號(:)操作符來繼承基礎類別(在派生類名或建構函式之後)。如下程式碼所示 -

// 宣告一個基礎類別
open class Base(p: Int){  

}

// 宣告一個繼承自 Base 類(也稱為基礎類別)的子類:Derived
class Derived(p: Int) : Base(p){  

}

假設有兩個不同的類:ProgrammerSalesman,它們具有公共屬性nameagesalary以及它們各自的方法:functionalitiesdoProgram()fieldWork()。 繼承的特性允許繼承包含公共特性的(Employee基礎類別)。

open class Employee(name: String, age: Int, salary: Float) {  
    // code of employee  
}  

class Programmer(name: String, age: Int, salary: Float): Employee(name,age,salary) {  
    // code of programmer  
}  

class Salesman(name: String, age: Int, salary: Float): Employee(name,age,salary) {  
    // code of salesman  
}

所有Kotlin類都有一個共同的超類Any,它是沒有明確指定超類時使用的預設超類。

例如,類Example是隱式繼承Any類的,即使沒有明確寫上。

class Example

Kotlin open關鍵字

由於Kotlin類預設為final,因此不能簡單地繼承它們。在類之前使用open關鍵字來為其它類繼承這個類。

範例:

open class Example{  
// I can now be extended!  
}

Kotlin繼承類中的欄位

當繼承一個類來派生類時,所有的欄位和函式都是繼承的。 可以在派生類中使用這些欄位和函式。

範例:

open class Base{
    val x = 10
}
class Derived: Base() {
    fun foo() {
        println("x is equal to " + x)
    }
}
fun main(args: Array<String>) {
    val derived = Derived()
    derived.foo()
}

執行上面範例程式碼,得到以下結果 -

x is equal to 10

Kotlin從類繼承方法

open class Bird {
    fun fly() {
        println("flying...")
    }
}
class Duck: Bird() {
    fun swim() {
        println("swimming...")
    }
}
fun main(args: Array<String>) {
    val duck = Duck()
    duck.fly()
    duck.swim()
}

執行上面範例程式碼,得到以下結果 -

flying...
swimming...

Kotlin繼承範例

在這裡,宣告一個類Employee是超類,ProgrammerSalesman是它的子類。 子類繼承屬性:name, agesalary 以及包含子類自身的函式,如:doProgram()fieldWork()

open class Employee(name: String, age: Int, salary: Float) {
    init {
        println("Name is $name.")
        println("Age is $age")
        println("Salary is $salary")
    }
}
class Programmer(name: String, age: Int, salary: Float):Employee(name,age,salary){
    fun doProgram() {
        println("programming is my passion.")
    }
}
class Salesman(name: String, age: Int, salary: Float):Employee(name,age,salary){
    fun fieldWork() {
        println("travelling is my hobby.")
    }
}
fun main(args: Array<String>){
    val obj1 = Programmer("Maxsu", 25, 40000f)
    obj1.doProgram()
    val obj2 = Salesman("Ajax", 24, 30000f)
    obj2.fieldWork()
}

執行上面範例程式碼,得到以下結果 -

Name is Maxsu.
Age is 25
Salary is 40000.0
programming is my passion.
Name is Ajax.
Age is 24
Salary is 30000.0
travelling is my hobby.

Kotlin繼承和主要建構函式

如果基礎類別和派生類都具有主建構函式,則引數在基礎類別的主建構函式中初始化。 在上面的繼承範例中,所有類都包含三個引數:nameagesalary,所有這些引數都在基礎類別的主建構函式中初始化。

當基礎類別和派生類在主建構函式中包含不同數量的引數時,基礎類別引數將從派生類物件初始化。

範例程式碼

open class Employee(name: String,salary: Float) {
    init {
        println("姓名:$name.")
        println("薪水:$salary")
    }
}
class Programmer(name: String, dept: String, salary: Float):Employee(name,salary){
    init {
        println("$name 所在部門:$dept ,薪水為:$salary.")
    }
    fun doProgram() {
        println("程式設計我有激情.")

    }
}
class Salesman(name: String, dept: String, salary: Float):Employee(name,salary){
    init {
        println("$name 所在部門:$dept ,薪水為:$salary.")
    }
    fun fieldWork() {
        println("我的愛好是:旅遊.")

    }
}
fun main(args: Array<String>){
    val obj1 = Programmer("Susen", "技術部", 40000f)
    obj1.doProgram()
    println()
    val obj2 = Salesman("Ajax", "市場部", 30000f)
    obj2.fieldWork()
}

執行上面範例程式碼,得到以下結果 -

姓名:Susen.
薪水:40000.0
Susen 所在部門:技術部 ,薪水為:40000.0.
程式設計我有激情.

姓名:Ajax.
薪水:30000.0
Ajax 所在部門:市場部 ,薪水為:30000.0.
我的愛好是:旅遊.

當建立派生類的物件時,它首先呼叫超類並執行基礎類別的init塊,然後執行它自己的init塊。

Kotlin繼承和輔助建構函式

如果派生類不包含任何主建構函式,則需要使用super關鍵字從派生類呼叫基礎類別輔助建構函式。

範例:

open class Patent {

    constructor(name: String, id: Int) {
        println("執行超類建構函式: $id , $name ")
    }
}

class Child: Patent {

    constructor(name: String, id: Int, dept: String): super(name, id) {
        print("使用屬性執行子類建構函式:$name, $id, $dept")
    }
}
fun main(args: Array<String>) {
    val child = Child("Maxsu",10010, "技術部")
}

執行上面範例程式碼,得到以下結果 -

執行超類建構函式: 10010 , Maxsu 
使用屬性執行子類建構函式:Maxsu, 10010, 技術部

在上面的範例中,當建立Child類的物件時,它呼叫其建構函式並使用值:「Maxsu」,「10010」和「技術部」初始化其引數。 同時,Child類建構函式使用具有nameid值的super關鍵字呼叫超類別建構函式。 由於super關鍵字的存在,超類建構函式的主體首先執行並返回到Child類建構函式。

Kotlin方法覆蓋

方法覆蓋意味著將super(parent)類的方法的特定實現提供到子類(子)類中。

換句話說,當子類重新定義或修改其超類的方法為子類時,它被稱為方法覆蓋。 方法覆蓋只能在繼承中實現。

Kotlin方法覆蓋的規則

  • 父類別及要覆蓋的方法或屬性必須是open的(非final)。
  • 基礎類別和派生類的方法名必須相同。
  • 方法必須具有與基礎類別相同的引數。

沒有覆蓋的繼承範例

open class Bird {
    open fun fly() {
        println("Bird is flying...")
    }
}
class Parrot: Bird() {

}
class Duck: Bird() {

}
fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    val d = Duck()
    d.fly()
}

執行上面範例程式碼,得到以下結果 -

Bird is flying...
Bird is flying...

在上面的例子中,一個沒有覆蓋基礎類別方法的程式出現派生類ParrotDuck類執行相同的操作。 為了克服這個問題,使用方法覆蓋這個概念。

Kotlin方法覆蓋的範例

在此範例中,子類ParrotDuck中覆蓋父類別Bird的方法fly()。 要覆蓋父類別的方法,必須將要覆蓋的父類別及方法宣告為open。 同時,在子類中重寫的方法必須以override關鍵字開頭。

open class Bird {
    open fun fly() {
        println("Bird is flying...")
    }
}
class Parrot: Bird() {
    override fun fly() {
        println("Parrot is flying...")
    }
}
class Duck: Bird() {
    override fun fly() {
        println("Duck is flying...")
    }
}
fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    val d = Duck()
    d.fly()
}

執行上面範例程式碼,得到以下結果 -

Parrot is flying...
Duck is flying...

Kotlin屬性覆蓋的範例

超類的屬性也可以在子類中覆蓋,這個實現類似於方法。 在子類ParrotDuck中重寫並修改Bird類的color屬性。

open class Bird {
    open var color = "黑色"
    open fun fly() {
        println("Bird is flying...")
    }
}
class Parrot: Bird() {
    override var color = "綠色"
    override fun fly() {
        println("Parrot is flying...")
    }
}
class Duck: Bird() {
    override var color = "花色"
    override fun fly() {
        println("Duck is flying...")
    }
}
fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    println(p.color)
    val d = Duck()
    d.fly()
    println(d.color)
}

執行上面範例程式碼,得到以下結果 -

Parrot is flying...
綠色
Duck is flying...
花色

可以在繼承中使用var屬性覆蓋val屬性,但反之亦然。

Kotlin超類實現

派生類也可以使用super關鍵字呼叫超類方法和屬性。

例如:

open class Bird {
    open var color = "黑色"
    open fun fly() {
        println("Bird is flying...")
    }
}
class Parrot: Bird() {
    override var color = "綠色"
    override fun fly() {
        super.fly()
        println("Parrot is flying...")
    }
}

fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    println(p.color)

}

執行上面範例程式碼,得到以下結果 -

Bird is flying...
Parrot is flying...
綠色

Kotlin多類實現

在Kotlin中,派生類在尖括號中使用超型別名稱,即,super <Base>,當它實現多個類中提供的相同函式名時。

例如,派生類Parrot擴充套件超類Bird並實現相同的Duck介面函式fly()。 要呼叫每個類和介面的特定方法,必須在尖括號中提到超型別名稱為super <Bird>.fly()super <Duck>.fly()

open class Bird {
    open var color = "黑色"
    open fun fly() {
        println("Bird is flying...")
    }
}
interface Duck {
    fun fly() {
        println("Duck is flying...")
    }
}
class Parrot: Bird(),Duck {
    override var color = "綠色"
    override fun fly() {
        super<Bird>.fly()
        super<Duck>.fly()
        println("Parrot is flying...")

    }
}
fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    println(p.color)

}

執行上面範例程式碼,得到以下結果 -

Bird is flying...
Duck is flying...
Parrot is flying...
綠色