天天看點

多态

  多态是同一個行為具有多個不同表現形式或形态的能力。同一個形參類型為基類的接口,使用不同的子類的執行個體可以執行不同操作。

綁定:将一個方法調用和一個方法體關聯起來被稱作綁定;

前期綁定:若在程式執行前進行綁定(如果有的話,由編譯器和連接配接程式實作);

後期綁定:在運作時根據對象的類型綁定,也叫做動态綁定或運作時綁定。

  後期綁定的實作通常是在對象中安置某種“類型資訊”,以便方法調用機制能知道對象是哪種類型,進而找到對應的方法體加以調用。

  Java中除了static方法和final方法(private方法也屬于final方法)之外,其他所有方法都是後期綁定。

  Java在使用基類引用調用方法時,總是調用最派生的方法。選取最派生方法的範圍是:基類中的方法和基類引用指向的對象所在類中覆寫的同名方法。即,如果基類引用所指向對象所在的類中未覆寫基類中的方法,那麼通過基類引用調用的将會是基類中的方法,否則調用的就是基類引用所指向對象所在類中覆寫的方法。

運作結果為:

如上代碼中的派生關系為:

多态

使用基類引用調用的方法是method1(),從BaseClass baseClass = new DerivedClass()可知選取最派生方法的範圍應該是BaseClass類和DerivedClass類,但DerivedClass中未覆寫BaseClass中的method1(),是以最派生的method1()方法就是BaseClass中的method1()。BaseClass中的method1()又調用了method2(),這裡實際上也可了解為是通過基類引用baseClass去調用的method2(),此時,因為DerivedClass中覆寫了method2(),是以選取最派生的方法就是DerivedClass類中的method2()。

  結論:final方法(包括private方法)、靜态方法和域沒有多态特性。

  final方法不可以被覆寫,是以同一個行為就不能有多種表現形式,是以沒有多态。注意:private方法是預設的final方法。

這裡還是可以根據1-3中的方式分析,從PrivateOverride privateOverride = new Derived()中可知,選取最派生f()方法的範圍為PrivateOverrie類和Derived類,但是Derived類中未覆寫f()方法(雖然有同名方法,但因為private方法不可能被覆寫,是以Derived類中的f()隻能算是另一個新方法),是以選取的範圍就隻剩下來基類中的f()方法,是以實際調用的方法就是基類中的f()方法。

  靜态方法對應的行為不具有多态性,靜态方法是與類而并非單個對象關聯的。

  如果直接通路某個域,這個通路在編譯期就進行了解析(并非是運作時綁定),是以域不具有多态性。

運作結果為: 

構造器不具有多态性,因為構造器實際上是隐式聲明的static方法,由2-2可知,靜态方法不具有多态性。

基類的構造器總是在導出類的構造過程中被調用;

無論是基類還是導出類,在構造器被調用時,所有成員變量都已經完成了初始化。

調用構造器的順序為:

1)調用基類構造器。這個步驟會不斷反複遞歸下去,首先是構造這個層次結構的根(根基類),然後是下一層的導出類,直到最低層的導出類(構造器執行前需保證類中的所有成員按聲明順序完成了初始化);

2)按聲明順序調用最低層導出類的初始化方法;

3)調用最低層導出類構造器的主體。

如果要在基類構造器中調用一個可被動态綁定的方法,實際上調用時綁定的方法體可能會是導出類中覆寫此方法的方法體。這個調用結果可能會引發錯誤,因為在調用基類構造器時,導出類對象還未被完全構造。(在構造導出類對象時候,會先調用基類的構造器。)

Glyph.draw()方法設計為将要被覆寫,這種覆寫是在RoundGlyph中發生的。但是Glyph構造器會調用這個方法,結果導緻了對RoundGlyph.draw()的調用。但是此時RoundGlyph中的radius還未被初始化(還是二進制0)。

初始化的具體過程:(->)https://www.cnblogs.com/certainTao/p/14657469.html

編寫構造器的準則:用盡可能簡單的方法使對象進入正常狀态;如果可以的話,避免調用其他方法。

在構造器中唯一能夠安全調用的方法是本類中的final方法(private方法預設是final方法),這類方法不能被覆寫(其實調用靜态方法也是可以的,但這裡要表明的重點不是這個)。

繼續閱讀