在 OOP 裡,class 的繼承也是一個很重要的特色,跟 Java 一樣,Kotlin 只能單一繼承,不能繼承多類別。
open 和 final 是一對相反意義的關鍵字
這裡我們延用之前的例子 Wallet
先建立子類別 (MyWallet) 來繼承父類別 (Wallet)
在 Kotlin 中繼承使用 :
符號
class MyWallet : Wallet {
}
會發現, Wallet 是 final 不可以被繼承,因為預設 class 都是 final 的
所以把 Wallet 加上 open
open class Wallet(val id: Long, _balance: BigDecimal, _createTime: LocalDateTime) {
但發現 Wallet 至少需要 id 這個初始 constuctor
所以修改後會是這樣
class MyWallet : Wallet(123) {
}
如果想要覆寫父類別的方法,要用 override 關鍵字,而且父類別的方法也要宣告成 open
像這樣
open class Wallet(val id: Long, _balance: BigDecimal, _createTime: LocalDateTime) {
open fun increaseBalance(amount: BigDecimal) {
....
}
}
一樣父類別的屬性要宣告 open,這裡還用了 protected 來限制只有類別和子類別可以看見這個屬性。
open class Wallet(val id: Long, _balance: BigDecimal, _createTime: LocalDateTime) {
.....
protected open var paymentWay: PaymentWay? = PaymentWay("Apple Pay")
}
class MyWallet : Wallet(123) {
override var paymentWay: PaymentWay? = PaymentWay("My Apple pay")
...
}
同理,如果要讓其他子類別繼承 MyWallet,MyWallet class 也要宣告成 open
MyWallet override 的 function 或 property 預設都是 open 的,所以如果不要讓其他 subclass override 的話,可以加上 final
如下面的例子
open class MyWallet : Wallet(123) {
final override var paymentWay: PaymentWay? = PaymentWay("My Apple pay")
...
}
這樣其他繼承 MyWallet 的 subclass 就無法覆寫 paymentWay
如果要在子類別訪問父類別呢? 就要使用 super 這個關鍵字
constructor 的用法
class MyWallet : Wallet {
constructor(id: Long) : super(id)
}
但注意有用 constructor 就不能這樣用預設的寫法了
super.屬性 和 super.方法
override fun increaseBalance(amount: BigDecimal) {
println("MyWallet super.balance ${super.balance}")
super.increaseBalance(amount)
println("MyWallet increaseBalance $amount")
}
在 Java 中,我們可以用 instanceOf 去檢查一個 class 屬於什麼 class type
在 Kotlin 中,則是使用 is
val myWallet = MyWallet()
println(myWallet is Wallet) // true
println(wallet is MyWallet) // false
如同在 Java 有個 Object 的 class 是所有 class 的父類別
在 Kotlin 則是 Any 這個 class
所以像下面的例子,anyFun(any: Any) 我們可以傳入任意 type 的參數進去。
fun main() {
anyFun(myWallet) //it's MyWallet
}
fun anyFun(any: Any) {
if (any is MyWallet) {
println("it's MyWallet")
} else {
println("it's other type")
}
}
但是跟在 Java 一樣,如果無法得知確切的 class type 是無法呼叫真正的 class 下相關的 function 的
所以這時候要使用 as
做強制轉型
(any as MyWallet).decreaseBalance(BigDecimal(200))
Kotlin 很聰明,如果像下面的例子,因為一開始我們就有判斷 any 是不是 MyWallet,所以其實在判斷後就可以直接使用了,不用再自己手動做轉型,這就是 smart cast
if (any is MyWallet) { // smart cast
println("it's MyWallet")
any.decreaseBalance(BigDecimal(0))
} else {
println("it's other type")
}
今天就講到這裡啦!謝謝大家,我們明天見!
今日練習的程式在這: 請點我