JAVA——多態之超類與子類的關係及方法調用

置換法則:

超類對象的任何地方都可以用子類對象置換。

 

一個超類變量既可以引用一個超類對象,也可以引用超類的任何一個子類的對象。如:

Manager boss = new Manager();
Employee[] staff = new Employee[3];
staff[0] = boss; 

其中Manager類爲Employee的子類。這個過程也被稱爲向上轉型,在向上轉型以後,這個超類變量只能訪問超類中定義的方法而不能調用子類中定義的方法,並且如果子類對這些方法進行了重寫(override),則調用的是重寫後的方法。爲了理解虛擬機如何分辨調用哪個方法,需要理解方法調用。

方法調用:

(1)編譯器查看對象的聲明類型和方法名。如果要調用x.f(param)方法,編譯器首先一一列舉x對象所屬類中名爲f的方法和其父類中訪問屬性爲public且名稱爲f的方法(子類不能訪問超類的私有方法)。

(2)編譯器查看方法調用的參數類型。這一步從各個重載(overload)的方法中找出調用的方法。但是可能子類和超類中都存在這個方法(子類繼承或者重寫超類的這個方法)。

(3)靜態綁定或動態綁定:

如果這個方法在超類中是被private,static或者final修飾,則可以通過靜態綁定判斷調用哪個方法,因爲這些方法都不能被子類重寫(override),所以編譯器可以直接判斷:

①private修飾的方法被子類繼承但無法直接訪問,相當於對子類隱藏,因此無法被重寫(override)。因此雖然可能名稱和參數類型一樣,但是可以把子類中的方法看成與超類中private方法無關的方法。因此編譯器可以直接分辨這個方法屬於哪個類(子類中有則屬於子類,子類只是從超類繼承則屬於超類)。

②static修飾的方法可以被子類繼承,但是不能被重寫。與private類型修飾類似,這種同名同參數的方法可以稱之爲重定義,或者說被子類隱藏,但實際兩個方法並沒有關係。如果是子類對象,則調用的是子類的方法,如果是超類對象,則調用的是超類的方法;如果是向上轉型,則調用的是超類的方法。

③final修飾的方法可以被繼承,但是不能被重寫,如果子類對象調用繼承的final方法,實際上是調用的父類的方法。可以用final修飾方法達到關閉動態搜索的目的。在這種情況下,即使是子類對象,實際調用的還是超類的final方法。

如果不是由private、static、final修飾的方法,則編譯器需要通過動態綁定判斷使用哪個方法:

①虛擬機提取這個對象的實際類型的方法表,即這個對象變量(堆)指向的對象引用(棧)的類型的方法表(method table)。

②虛擬機搜索符合所調用的方法的簽名的類,這時虛擬機已經知道調用哪個方法。

③虛擬機調用方法。

方法調用總結:

當沒有向上轉型時,若是子類中與超類中的private和static方法同名的方法,此時仍調用子類的方法(重定義,靜態綁定)。

當爲向上轉型時,若是子類中與超類中的private和static方法同名的方法,此時調用父類中的方法(重定義,靜態綁定);若沒有用private或者static修飾,則調用子類中的方法(重寫,動態綁定);向上轉型時使用的是超類的對象變量,不能調用子類自己定義的方法。

在父類中final修飾的子類不能重寫,不管有無轉型都是調用父類的方法。

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