Kotlin - 繼承



繼承可以定義為一個類獲取另一個類的成員(方法和屬性)的過程。透過使用繼承,資訊以分層順序進行管理。

繼承其他類成員的類被稱為子類(派生類或子類),其成員被繼承的類被稱為超類(基類或父類)。

繼承是面向物件程式設計的關鍵特性之一,它允許使用者從現有類建立新類。透過繼承,我們可以繼承基類中的所有特性,並可以擁有自己的附加特性。

Kotlin 中的所有類都有一個共同的超類,稱為Any,它是未宣告任何超型別的類的預設超類。

class Example // Implicitly inherits from Any

Kotlin 超類Any 有三個方法:equals()hashCode()toString()。因此,這些方法為所有 Kotlin 類定義。

在 Kotlin 中,所有內容預設情況下都是final,因此,我們需要在類宣告前面使用關鍵字open 來使其可被其他類繼承。Kotlin 使用運算子":" 來繼承類。

示例

請看以下繼承示例。

open class ABC {
   fun think () {
      println("Hey!! i am thiking ")
   }
}
class BCD: ABC(){ // inheritence happend using default constructor 
}

fun main(args: Array<String>) {
   var  a = BCD()
   a.think()
}

執行上述 Kotlin 程式後,將生成以下輸出

Hey!! i am thiking 

重寫方法

現在,如果我們想在子類中重寫think()方法,那麼我們需要考慮以下示例,在這個示例中我們建立了兩個類並重寫了子類中的一個函式。

open class ABC {
   open fun think () {
      println("Hey!! i am thinking ")
   }
}
class BCD: ABC() { // inheritance happens using default constructor 
   override fun think() {
      println("I am from Child")
   }
}
fun main(args: Array<String>) {
   var  a = BCD()
   a.think()
}

執行上述 Kotlin 程式後,將生成以下輸出

I am from Child 

用關鍵字override標記的成員本身是open的,因此可以在子類中重寫它。如果您想禁止再次重寫它,則必須將其設為final,如下所示

class BCD: ABC() {
   final override fun think() {
      println("I am from Child")
   }
}

重寫屬性

重寫機制對屬性的工作方式與對方法的工作方式相同。在超類上宣告並在派生類上重新宣告的屬性必須以關鍵字override為字首,並且它們必須具有相容的型別。

open class ABC {
   open val count: Int = 0
   
   open fun think () {
      println("Hey!! i am thinking ")
   }
}
class BCD: ABC() {
   override val count: Int
   
   init{
      count = 100
   }

   override fun think() {
      println("I am from Child")
   }
   
   fun displayCount(){
      println("Count value is $count")
   }
}
fun main(args: Array<String>) {
   var  a = BCD()
   a.displayCount()
}

執行上述 Kotlin 程式後,將生成以下輸出

Count value is 100
您還可以用var屬性重寫val屬性,反之則不行。這是允許的,因為val屬性實際上聲明瞭一個get方法,而將其重寫為var則在派生類中額外聲明瞭一個set方法。

我們還可以將override關鍵字用作主建構函式中屬性宣告的一部分。下面的示例使用主建構函式重寫count屬性,如果不向建構函式傳遞任何值,它將採用預設值400。

open class ABC {
   open val count: Int = 0
   
   open fun think () {
      println("Hey!! i am thinking ")
   }
}
class BCD(override val count: Int = 400): ABC() {

   override fun think() {
      println("I am from Child")
   }
   
   fun displayCount(){
      println("Count value is $count")
   }
}
fun main(args: Array<String>) {
   var a = BCD(200)
   var b = BCD()
   a.displayCount()
   b.displayCount()
}

執行上述 Kotlin 程式後,將生成以下輸出

Count value is 200
Count value is 400

派生類初始化順序

當我們建立派生類的物件時,建構函式初始化從基類開始。這意味著首先將初始化基類屬性,然後呼叫任何派生類建構函式,任何進一步的派生類也是如此。

這意味著當執行基類建構函式時,在派生類中宣告或重寫的屬性尚未初始化。

open class Base {
   init{
      println("I am in Base class")
   }
}
open class Child: Base() {
   init{
      println("I am in Child class")
   }
}
class GrandChild: Child() {
   init{
      println("I am in Grand Child class")
   }
}
fun main(args: Array<String>) {
   var a = GrandChild()
}

執行上述 Kotlin 程式後,將生成以下輸出

I am in Base class
I am in Child class
I am in Grand Child class

訪問超類成員

派生類中的程式碼可以使用super關鍵字直接呼叫其超類函式和屬性。

open class Base() {
   open val name:String
   init{
      name = "Base"
   }
   open fun displayName(){
      println("I am in " +  this.name)
   }
}
class Child(): Base() {
   override fun displayName(){
      super.displayName()
      println("I am in " + super.name)
  
   }
}
fun main(args: Array<String>) {
   var a = Child()
   a.displayName()
}

執行上述 Kotlin 程式後,將生成以下輸出

I am in Base
I am in Base

重寫規則

如果子類從其直接超類繼承相同成員的多個實現,則它必須重寫此成員並提供其自己的實現。

這與從單個父類繼承成員的子類不同,在這種情況下,子類不必提供所有開放成員的實現。

open class Rectangle {
    open fun draw() { /* ... */ }
}

interface Polygon {
    fun draw() { /* ... */ } // interface members are 'open' by default
}

class Square() : Rectangle(), Polygon {
    // The compiler requires draw() to be overridden:
    override fun draw() {
        super<Rectangle>.draw() // call to Rectangle.draw()
        super<Polygon>.draw() // call to Polygon.draw()
    }
}

RectanglePolygon兩者繼承都可以,但它們都具有draw()方法的實現,因此您需要在Square中重寫draw()併為其提供單獨的實現以消除歧義。

測驗時間 (面試和考試準備)

問1 - 用於使類可繼承的關鍵字是什麼?

A - abstract

B - override

C - open

D - 以上都不是

答案:C

解釋

Kotlin 使用關鍵字open 使任何類或其成員可繼承。

答案:D

解釋

從 Kotlin 繼承的角度來看,所有給定的語句都是正確的。

答案:C

解釋

關於在子類中訪問父類成員,給定的語句 A 和 B 是正確的。

廣告
© . All rights reserved.