Java開發筆記(五十七)因抽象方法而產生的抽象類
前面介紹了類的常見用法,令人感嘆面向對象的強大,幾乎日常生活中的所有事物,都可以抽象成Java的基類及其子類。然而抽象操作也有副作用,就是某個抽象而來的行為可能是不確定的,比如半夜雞叫,如果是公雞則必定“喔喔喔”地叫,如果是母雞則必定“咯咯咯”地叫,可要是不能確定這只雞是公雞還是母雞抑或小雞,系統怎麽知道它會怎麽叫?落實到雞類Chicken的定義代碼中,它的call方法便無法給出具體的叫聲了,盡管雞類能夠派生出公雞類和母雞類,再在公雞類和母雞類重寫call方法,但是外部仍然可以創建雞類的實例,接著調用雞類實例的call方法,此時該期望這只雞發出什麽叫聲呢?不管是讓雞類胡言亂語、語無倫次,還是讓雞類默不作聲、噤若寒蟬,顯然都與真實情況有很大出入。
由此可見,某些類其實並不能拿來直接使用,充其量只能算半成品,必須經過進一步的加工,形成最終的成品方能給外部調用。鑒於前述的雞類存在叫喚這個不確定的方法,故而理應將它歸入半成品之列;至於由雞類派生而來的公雞類與母雞類,因為包括叫喚在內的每個方法都是明確的,所以它們才成為機能鑒權的完整類。在Java編程中,功能不確定的方法被稱作抽象方法,而包含抽象方法的類受到牽連就變成了抽象類。在類的定義代碼裏面,通過關鍵字abstract來標識抽象方法及抽象類;凡是被abstract修飾的抽象方法,由於方法的具體實現並不明確,因此抽象方法沒有花括號所包裹著的方法體;凡是被abstract修飾的抽象類,由於包含了至少一個抽象方法,因此不允許外部創建抽象類的實例,否則就會出現雞類實例不知如何叫喚的尷尬。除此之外,抽象類還有下列兩點需要註意:
1、abstract只能用來修飾抽象方法和抽象類,不可用於修飾成員屬性,因為屬性值本身就允許通過賦值來改變,無所謂抽象不抽象。
2、雖然抽象類依舊可以擁有構造方法,但它的構造方法並不能被外部直接調用,因為外部不允許通過構造方法來創建抽象類的實例,抽象類的構造方法只能提供給它的子類調用。
絮絮叨叨了這麽多抽象概念,接著嘗試把之前的雞類改寫成抽象類,修改後的抽象雞類定義代碼示例如下:
//演示抽象類的定義 abstract public class Chicken { // 定義一個名稱屬性 public String name; // 定義一個性別屬性 public int sex; // 定義一個抽象的叫喚方法。註意後面沒有花括號,並且以分號結尾 abstract public void call(); // 即使抽象類定義了構造方法,外部也無法創建它的實例 public Chicken() { } // Java只有抽象類和抽象方法,沒有抽象屬性的說法 //abstract public String cry; }
然後分別編寫繼承自雞類的公雞類和母雞類,其中雞類的抽象方法call是必須在子類中重寫的,只有這樣,派生而來的子類才具備所有完善的行為動作;否則的話,這個子類仍舊是個尚未完工的半成品,依然屬於抽象類的行列。下面是重寫了call方法的公雞類代碼例子:
//定義一個繼承自抽象雞類的公雞類 public class Cock extends Chicken { public Cock() { // 公雞的性別固定為雄性 sex = 0; } // 重寫了公雞的叫喚方法。如果不重寫父類的抽象方法,那麽該子類仍舊為抽象類 public void call() { System.out.println("喔喔喔"); } }
同樣重寫了call方法的母雞類代碼如下所示:
//定義一個繼承自抽象雞類的母雞類 public class Hen extends Chicken { public Hen() { // 母雞的性別固定為雌性 sex = 1; } // 重寫了母雞的叫喚方法。如果不重寫父類的抽象方法,那麽該子類仍舊為抽象類 public void call() { System.out.println("咯咯咯"); } }
最後輪到外部調用各種雞類了,對於外部而言,唯一的區別是外部不能創建抽象類的實例,其它子類的調用則跟從前一樣沒有變化。具體的外部調用代碼見下:
// 不能創建抽象類的實例,因為抽象類是個尚未完工的類 //Chicken chicken = new Chicken(); // 創建一個公雞實例,公雞類繼承自抽象類Chicken Cock cock = new Cock(); cock.call(); // 調用公雞實例的叫喚方法 // 創建一個母雞實例,母雞類繼承自抽象類Chicken Hen hen = new Hen(); hen.call(); // 調用母雞實例的叫喚方法
運行上面的調用代碼,得到以下的日誌結果,可見子類重寫後的call方法正常工作。
喔喔喔 咯咯咯
更多Java技術文章參見《Java開發筆記(序)章節目錄》
Java開發筆記(五十七)因抽象方法而產生的抽象類