繼承


你 建立了一個銀行帳戶類別:
class Account(val id: String, val name: String) {
protected var bal: Int = _

def deposit(amount: Int) {
require(amount > 0)
bal += amount
}

def withdraw(amount: Int) {
require(amount > 0)
if(amount <= bal) {
bal -= amount
}
else {
throw new RuntimeException("餘額不足")
}
}

def balance = bal

override def toString = "Id:\t\t" + id +
"\nName:\t\t" + name +
"\nBalance:\t" + bal
}

在這個類別中,雖然沒有聲明,但你已經使用了繼承,在Scala中,如 果你沒有指定繼承任何類別,預設就是繼承scala.AnyRef(相當於Java的 java.lang.Object),在上面的例子中,你重新定義了AnyRef的toString方法,傳回帳戶資料的描述字串。

在Scala中,如果你要重新定義父類別中的成員,override 關鍵字是必要的,如果沒有標明override,編譯器會告訴你,你正定義一個父類別中已經有的成員:
error: error overriding method toString in class Object of type() java.lang.String; method toString needs `override' modifier
    def toString = "Id:\t\t" + id +
         ^
one error found

這避免你在不知情的情況下,重新定義了某個父類別的成員,override的另一個作用是,如果你指定要override某個成員,但父類別 中根本不存在該成員(也許是你打錯字了),編譯器也會提出警訊:
error: method tString overrides nothing
    override def tString = "Id:\t\t" + id +
                  ^
one error found

假設你為以上的類別建立了一個支票帳戶:
class CheckingAccount(override val id: String, override val name: String) 
extends Account(id, name) { // 繼承並呼叫父類別建構式
private var limit: Int = 30000

def overdraftLimit = limit
def overdraftLimit_=(amount: Int) {
require(amount > 0)
limit = amount
}

override def withdraw(amount: Int) {
require(amount > 0)
if(amount <= bal + overdraftLimit) {
bal -= amount
}
else {
throw new RuntimeException("超出信用")
}
}

override def toString = super.toString +
"\nOverdraft limit:" + overdraftLimit
}

在Scala中,使用extends來指定要繼承自哪個類別,如果需要 呼叫父類別建構式,則只有主要建構式能夠呼叫,輔助建構式是不能呼叫父類別建構式的。由於 bal在父類別中是宣告為protected,所以可以(也僅能)在子類別中使用(跟Java不同的是,Scala的protected並沒 有package-private的含義)。如果在子類別中,打算呼叫父類別的方法,則可以如範例中,使用super來呼叫。

上例中,由於id與name的定義,與父類別是一致的,所以必須使用override指明,你要定義的成員確實是與父類別相同的,如果你不使 用override:
class CheckingAccount(val id: String, val name: String)
           extends Account(id, name) {

    ....
}

則編譯器也會提醒你,你正試圖定義父類別已有的成員:
error: error overriding value id in class Account of type String; value id needs `override' modifier
class CheckingAccount(val id: String, val name: String)
                           ^
error: error overriding value name in class Account of type String; value name needs `override' modifier
class CheckingAccount(val id: String, val name: String)
                                           ^
two errors found

如果你在定義類別時,加上final關鍵字,則該類別將不再能被繼承,例如:
final class SuperAccount   // 這個類別不能被繼承

如果在類別中定義方法時,加上final關鍵字,則子類別不可以重新定義該方法:
class FakeAccount {
final def withdraw(amount: Int) = 0 // 不能被重新定義
}