8.5.2.3 方法覆蓋
前面介紹了繼承的一些基礎知識,現在介紹一些在使用繼承時需要注意的問題。熟悉這些問題將更好的解決項目中的實際問題。
例如在實際的游戲中,會按照怪物的種類實現設計。首先設計一個基礎類Monster,然後按照怪物類別設計Monster的子類,如Boss、NormalMonster等。則在實際實現時,每個怪物都有移動(move)的功能,但是在Boss和NormalMonster的移動規則存在不同。這樣就需要在子類的內部重新編寫移動的功能,從而滿足實際的移動要求。該示例的實現代碼如下:
//Monster.java
public class Monster{
public void move(){
//移動功能
}
}
//Boss.java
public class Boss extends Monster{
public void move(){
//Boss類的移動規則
}
}
//NormalMonster.java
public class NormalMonster extends Monster{
public void move(){
// NormalMonster類的移動規則
}
}
這樣在Monster的每個子類內部都重新書寫了move方法的功能,這種在子類內部重新父類中的方法的語法現象,稱作方法覆蓋(override)。
方法覆蓋在實際中保持了類的結構的統一,在實際使用時將極大的方便程序開發人員的使用,使項目的整體結構保持統一,便於項目的維護。
在使用子類的對象時,子類內部的方法將覆蓋從父類繼承過來的方法,也就是說子類的對象調用的是子類的功能方法,而不是父類的方法。
在進行方法覆蓋時,子類內部的方法和父類的方法聲明相同,而且子類方法的限制不能比父類的方法嚴格。例如不能使用比父類限制更大的訪問控制符或拋出比父類更多的異常等,這個在實際使用方法覆蓋時需要特別的注意。
在實際的項目中大量的存在需要在子類內部重寫父類的功能方法的地方,恰當的使用方法覆蓋將為項目開發帶來很大的便利。
8.2.2.4 需要注意的問題
除了方法覆蓋以外,在實際使用繼承時還有很多需要注意的問題。下面就這些問題進行一一說明。
1、屬性覆蓋沒有必要
方法覆蓋可以重寫對應的功能,在實際繼承時在語法上也支持屬性覆蓋(在子類內部聲明和父類屬性名相同的屬性),但是在實際使用時修改屬性的類型將導致類結構的混亂,所以在繼承時不能使用屬性覆蓋。
2、子類構造方法的書寫
該項是繼承時書寫子類最需要注意的問題。在子類的構造方法內部必須調用父類的構造方法,為了方便程序員進行開發,如果在子類內部不書寫調用父類構造方法的代碼時,則子類構造方法將自動調用父類的默認構造方法。而如果父類不存在默認構造方法時,則必須在子類內部使用super關鍵字手動調用,關於super關鍵字的使用將在後續進行詳細的介紹。
說明:子類構造方法的參數列表和父類構造方法的參數列表不必完全相同。
3、子類的構造過程
在構造子類時由於需要父類的構造方法,所以實際構造子類的過程就顯得比較復雜了。其實在實際執行時,子類的構造過程遵循:首先構造父類的結構,其次構造子類的結構,無論構造父類還是子類的結構,都是首先初始化屬性,其次執行構造方法。則子類的構造過程具體如下:
如果類A是類B的父類,則類B的對象構造的順序如下:
a)類A的屬性初始化
b)類A的構造方法
c)類B的屬性
d)類B的構造方法
由於任何一個類都直接或間接繼承自Object類,所以Object類的屬性和構造方法都是首先執行的。
4、不要濫用繼承
在實際的項目設計中,繼承雖然很經常使用,但是還是不能濫用,使用繼承的場合以及相關問題參看下面的說明。
8.5.2.5 如何設計繼承
在實際的項目中,類和類之間的關系主要有三種:
1、沒有關系
項目中的兩個類之間沒有關聯,不需要進行消息傳遞,則這兩個類之間就沒有關系,可以互相進行獨立的設計。
2、使用關系(has-a)
如果一個類的對象是另外一個類的屬性,則這兩個類之間的關系是使用關系。例如把房屋(House)看作是一個類,把門(Door)看成另外一個類,則房屋有一個門,代碼的實現如下:
//House.java
public class House{
public Door door;
}
//Door.java
public class Door{
}
則這裡Door的對象是House類的屬性,則Door和House類之間的關系就是使用關系,House使用Door類來制作自身。
使用關系提供了使用已有類來聲明新類的方式,可以以組合的方式來構建更復雜的類,這是項目中使用類的常見方式之一。
判斷是否是使用關系的依據就是:has-a,一個類具備另外一個類的對象,例如一個House有一個門。
3、繼承關系(is-a)
如果一個類是另外一個類的一種,也就是在分類上存在包含關系,則應該使用繼承來實現。例如Boss是怪物的一種,則使Boss繼承Monster類。
下面簡單介紹一些項目中繼承的設計方法。在實際設計繼承時,一般有兩種設計的方法:
1、自上而下的設計
在實際設計時,考慮類的體系結構,先設計父類,然後根據需要來增加子類,並在子類的內部實現或添加對應的方法。
2、自下而上的設計
在實際設計時,首先不考慮類的關系,每個類都分開設計,然後從相關的類中把重復的屬性和方法抽象出來形成父類。
對於初學者來說,第二種設計方式相對來說比較容易實現,所以一般初學者都按照第二種設計方式進行設計,設計完成以後再實現成具體的代碼。