參考鏈接: Java中將final與繼承一起使用
在之前的筆記Java靜態屬性和方法的繼承問題中,通過具體的實驗證明,在子類中重寫父類的字段時并沒有覆蓋父類的字段,只是隱藏了父類的字段。而在scala中則不同,scala子類的同名字段會重寫且覆蓋父類的同名字段,這里做了個簡單實驗,并記錄下來。?
Parent.scala?
class Parent {
? val normalStr: String = "Normal member of parent."
?
? def normalMethod() = {
? ? println("Normal method of parent.")
? }
}?
定義了一個字段normalStr和一個方法normalMethod(),在Scala中,類的字段是由一個私有屬性和對應的getter/setter方法組成的。?
Child.scala?
class Child extends Parent {
? override val normalStr: String = "Normal member of child."
?
? override def normalMethod() = {
? ? println("Normal method of child.")
? }
}?
子類Child繼承了父類Parent,并override父類的normalStr和normalMethod()。?
TestMain和Result?
object TestMain{
? def main(args: Array[String]) {
? ? val child: Child = new Child
? ? println(child.normalStr)
? ? child.normalMethod()
?
? ? //val child1:Parent = child.asInstanceOf[Parent]
? ? //采用Parent類型的變量指向創建的Child對象
? ? val child1:Parent = new Child
? ? println(child1.normalStr)
? ? child1.normalMethod()
? }
}?
輸出的結果如下:?
Normal member of child.
Normal method of child.
Normal member of child.
Normal method of child.?
從結果可以看出,子類重寫并覆蓋了父類的同名屬性和方法?
Scala子類的構造順序?
這里順便記錄下Scala子類的構造順序,這里直接用書上給出的例子,以便后續查看:?
先寫兩個類,一個父類Creature.scala,一個子類Ant.scala:?
Creature?
class Creature {
? ? val range: Int = 10
? ? val env: Array[Int] = new Array[Int](range)
? ? def show(): Unit = {
? ? ? ?println(range)
? ? }
}?
Ant?
class Ant extends Creature {
? ? override val range = 2
}?
現在創建一個Ant的對象ant,那么ant.env.length的值是多少,憑第一感覺應該是10或者2,然而答案是0,接下來我寫下ant創建的過程中構造器的運行順序:?
首先調用父類Creature的構造器(父類的構造器先于子類的構造器被調用),所以首先把range設置為10。為了后續的說明這里說明下,類的字段是由一個私有屬性和對應的getter和setter方法組成的,而子類在重寫父類的同名字段時,對于val類型的屬性子類重寫了getter方法。接下來初始化env數組,所以需要調用range的getter方法,然而子類已經重寫了getter方法,且子類并沒初始化,所有的字段都是對象創建過程中,內存清零后的默認值,所以此時range的值為0。這也就解釋了上述問題的疑問。接下來調用子類的構造器,range被設為2。?
所以在構造器中,對象的初始化不應該依賴于val的值,因為val的值對應的getter方法可能會被子類重寫覆蓋。解決辦法有:?
將val聲明為final。(簡單高效,但是不夠靈活)在超類中將val聲明為lazy。(簡單靈活,但是不夠高效)還有種就是子類中使用提前定義語法。(這個就不介紹了)?
ant對象調用show()方法輸出的則是子類range的值,即為2。而在Java中,則是父類的range的值:10。主要原因還是由于在Scala中,子類重寫父類的屬性或者方法,覆蓋了父類的屬性和方法,而在Java中,只有非靜態的方法會被子類重寫覆蓋,而非靜態/靜態屬性和靜態方法都只是被隱藏了。?
主要參考:《快學Scala》