Kotlin教學 | 從零開始學Kotlin | Kotlin入門 | CH08: 繼承(Inheritance)

繼承

以下是 Kotlin 繼承 的基礎概念,包括類別的定義、open 關鍵字、覆寫方法、屬性、多型(Polymorphism)、抽象類別等。


1. 繼承的基本概念

在 Kotlin 中:

  1. 類別預設為 final,無法被繼承。如果需要繼承,父類別必須使用 open 關鍵字修飾。
  2. 子類別使用 : 語法繼承父類別。
  3. 子類別必須直接或間接呼叫到父類別的構造函數。

語法

open class 父類別名稱 {
    // 父類別內容
}

class 子類別名稱 : 父類別名稱() {
    // 子類別內容
}

2. 簡單範例

範例:定義父類別和子類別

open class Animal {
    fun eat() {
        println("This animal is eating.")
    }
}

class Dog : Animal()

fun main() {
    val dog = Dog()
    dog.eat() // 輸出:This animal is eating.
}

3. 覆寫方法

父類別的方法或屬性如果要被覆寫,必須用 open 關鍵字修飾,而子類別需要用 override 關鍵字進行覆寫。

範例:

open class Animal {
    open fun sound() {
        println("Some generic animal sound.")
    }
}

class Dog : Animal() {
    override fun sound() {
        println("The dog barks.")
    }
}

fun main() {
    val animal: Animal = Dog()
    animal.sound() // 輸出:The dog barks.
}

4. 覆寫屬性

與方法類似,屬性必須使用 open 關鍵字修飾才能被覆寫。

範例:

open class Animal {
    open val sound: String = "Some generic animal sound"
}

class Dog : Animal() {
    override val sound: String = "Bark"
}

fun main() {
    val dog = Dog()
    println(dog.sound) // 輸出:Bark
}

5. 呼叫父類別方法

使用 super 關鍵字來呼叫父類別的方法或存取屬性。

範例:

open class Animal {
    open fun sound() {
        println("Some generic animal sound.")
    }
}

class Cat : Animal() {
    override fun sound() {
        super.sound() // 呼叫父類別的 sound 方法
        println("The cat meows.")
    }
}

fun main() {
    val cat = Cat()
    cat.sound()
    // 輸出:
    // Some generic animal sound.
    // The cat meows.
}

6. 呼叫父類別的構造函數

  1. 子類別必須直接或間接呼叫到父類別的構造函數。
  2. 子類別的主構造函數使用 : 父類別名稱(...) 語法,呼叫父類別的構造函數。
  3. 子類別的次構造函數使用 : super(...) 語法,呼叫父類別的構造函數。

範例 1:子類別主構造函數呼叫父類別

open class Animal(val name: String) {
    init {
        println("Animal initialized with name: $name")
    }
}

class Dog(name: String, val breed: String) : Animal(name) {
    init {
        println("Dog initialized with breed: $breed")
    }
}

fun main() {
    val dog = Dog("Buddy", "Golden Retriever")
    // 輸出:
    // Animal initialized with name: Buddy
    // Dog initialized with breed: Golden Retriever
}

解釋

  1. 父類別 Animal 的構造函數需要 name 參數。
  2. 子類別 Dog 使用 : Animal(name) 調用父類別構造函數。
  3. 父類別的 init 區塊先執行,接著執行子類別的 init 區塊。

範例2:子類別次構造函數呼叫父類別

open class Animal {
    val name: String

    constructor(name: String) {
        this.name = name
        println("Animal initialized with name: $name")
    }
}

class Dog : Animal {
    val breed: String

    constructor(name: String, breed: String) : super(name) {
        this.breed = breed
        println("Dog initialized with breed: $breed")
    }
}

fun main() {
    val dog = Dog("Buddy", "Labrador")
    // 輸出:
    // Animal initialized with name: Buddy
    // Dog initialized with breed: Labrador
}

解釋

  1. 父類別 Animal 提供了一個次建構函數(constructor)。
  2. 子類別 Dog 在其次建構函數中,使用 : super(name) 調用父類別的次建構函數。
  3. 初始化順序仍然是先執行父類別的初始化邏輯,然後執行子類別的初始化邏輯。

7. 抽象類別

抽象類別無法直接實例化,通常用於定義通用行為,由子類別實現具體內容。

範例:

abstract class Animal {
    abstract fun sound()
}

class Dog : Animal() {
    override fun sound() {
        println("The dog barks.")
    }
}

fun main() {
    val dog = Dog()
    dog.sound() // 輸出:The dog barks.
}

8. 多型(Polymorphism)

多型允許父類別型別的變數指向子類別的實例,並執行子類別覆寫的行為。

範例:多型應用

open class Animal {
    open fun sound() {
        println("Some generic animal sound.")
    }
}

class Dog : Animal() {
    override fun sound() {
        println("The dog barks.")
    }
}

class Cat : Animal() {
    override fun sound() {
        println("The cat meows.")
    }
}

fun main() {
    val animals: List<Animal> = listOf(Dog(), Cat())

    for (animal in animals) {
        animal.sound()
    }
    // 輸出:
    // The dog barks.
    // The cat meows.
}

9. 繼承與可見性修飾符

可見性修飾符

  • public(預設):所有地方可見。
  • protected:僅子類別可見。
  • internal:同一模組內可見。
  • private:僅限類別內部可見。

範例:使用 protected

open class Animal {
    protected fun protectedMethod() {
        println("This is a protected method.")
    }
}

class Dog : Animal() {
    fun callProtected() {
        protectedMethod() // 可以訪問 protected 方法
    }
}

fun main() {
    val dog = Dog()
    dog.callProtected() // 輸出:This is a protected method.
}

10. 繼承的限制:final 關鍵字

使用 final 關鍵字可以禁止繼承或覆寫。

範例:禁止繼承或覆寫

open class Animal {
    final fun sound() {
        println("This sound cannot be overridden.")
    }
}

class Dog : Animal() {
    // override fun sound() { } // 錯誤:無法覆寫被 final 修飾的方法
}

fun main() {
    val dog = Dog()
    dog.sound() // 輸出:This sound cannot be overridden.
}

Reference

https://kotlinlang.org/docs/inheritance.html

發佈留言