《Java編程思想》學習筆記:多態

一、後期綁定

對象能夠向上轉型,才能表現出多態。那麼爲什麼可以向上轉型呢?這裏我們需要了解一下幾個概念:

  • 綁定: 將一個方法調用同一個方法的主體聯繫起來,稱作“綁定”;
  • 前期綁定:在程序執行之前進行綁定;
  • 後期綁定:在程序運行時根據對象的類型進行綁定,我們也稱“動態綁定”或者“後期綁定”(java中除了static方法和final方法之外,其中,private方法屬於final方法,都是屬於後期綁定的方法);

注意:final 可以“關閉”動態綁定,這樣編譯器不需要對其進行動態綁定,可以爲final方法調用生成更有效的代碼。但是,我們最好根據設計來決定是否使用final,而不是試圖提高性能。

所以說,由於後期綁定這種機制的存在,我們在進行方法的調用時,可以直接只關注基類對象,在運行時,會找到真正的導出類的對象,並調用對象的方法。如此,我們能夠順利的完成向上轉型,並使得導出類的方法能夠得到正確的調用。此時,我們站在基類的角度來看,相同的方法對於不同的導出類而言,可以執行各自不同的任務,這樣就表現出了多種形態既多態。

二、構造器調用順序

但是,如何保證這種向上轉型能夠順利完成呢?

我覺得那是因爲我們在類初始化的時候有一套機制進行了保護,既當我們創建一個複雜類的時候,我們在進行構造時有指定的執行順序。構造器調用順序如下:

  • 調用基類構造器(不斷遞歸下去,從最底層的基類開始);
  • 按聲明順序調用成員的初始化方法;
  • 調用導出類構造器的主體;

這麼做的目的是保證所有基類成員以及當前對象都被初始化了。

注意一:

當我們進行清理工作時,應該先對導出類進行清理,然後纔是基類,因爲導出類可能使用的基類的某些方法等,這時是和聲明的順序相反的。

注意二:

用儘可能簡單的方法使對象進入正常狀態,如果可以的話,避免調用其他方法。舉例來說,如果B繼承了A,如果我們在A的構造初始化過程中掉用了a方法,但是a方法不是final(包含了private)的,那麼根據後期綁定的機制,就會調用導出類中a’方法,顯然,這個時候a’方法覆蓋了a方法,但是B類初始化還沒有完成,也就是說某些成員變量的初始值爲0或者null,在這種情況下,就很有可能報錯啦。

三、多態的設計

  • 1、繼承與組合

在我們創建新的類的時候,我們應該優先選擇“組合”來設計,然後以“繼承”輔助,因爲組合來說,直接可以知道某某的行爲,但是就繼承而言,你必須要知道該類的具體類型才能找到相應的行爲。如果,我們在一個地方需要表現爲不同的狀態的時候,可以考慮通過繼承來設計,達到相同的”調用“,表現出不同的行爲,從而表現出了多態的優勢。

  • 2、純繼承與擴展

通過繼承的關係我們可以從基類導出不同的子類,子類可以在基類的基礎上擴展增加自有的方法等,這樣我們可以輕鬆的擁有了基類的方法的同時還可以增加自己的方法。

  • 3、向下轉型與運行時類型識別

我們知道,導出類自有擴展的方法是基類沒有的,所以,如果我們向上轉型爲基類的類型,那麼該基類的導出類自有的方法就會無法調用,這個時候我們需要進行向下轉型,還原成導出類的對象,在轉型的過程中,是沒有任何損失的。但是,我們向下轉型是不安全的,因爲導出類具有大於基類的接口,所以我們在運行會進行檢測,如果有錯誤便會拋出異常。

小結

多態,意味着“不同的形式”。在面向對象的程序設計中,我們持有從基類繼承而來的相同的接口,以及使用該接口的不同形式:不同版本的動態綁定方法。這裏的接口,是我們必須要理解的。我們可以認爲,每一個類的N個方法實際可以抽離出來,看成這個類實現了N個接口。從接口的角度來看待類的方法,是很有必要的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章