繼承
以下是 Kotlin 繼承 的基礎概念,包括類別的定義、open
關鍵字、覆寫方法、屬性、多型(Polymorphism)、抽象類別等。
1. 繼承的基本概念
在 Kotlin 中:
- 類別預設為
final
,無法被繼承。如果需要繼承,父類別必須使用open
關鍵字修飾。 - 子類別使用
:
語法繼承父類別。 - 子類別必須直接或間接呼叫到父類別的構造函數。
語法
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. 呼叫父類別的構造函數
- 子類別必須直接或間接呼叫到父類別的構造函數。
- 子類別的主構造函數使用
: 父類別名稱(...)
語法,呼叫父類別的構造函數。 - 子類別的次構造函數使用
: 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
}
解釋
- 父類別
Animal
的構造函數需要name
參數。 - 子類別
Dog
使用: Animal(name)
調用父類別構造函數。 - 父類別的
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
}
解釋
- 父類別
Animal
提供了一個次建構函數(constructor
)。 - 子類別
Dog
在其次建構函數中,使用: super(name)
調用父類別的次建構函數。 - 初始化順序仍然是先執行父類別的初始化邏輯,然後執行子類別的初始化邏輯。
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.
}