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...
綠色