我們知道,面向?qū)ο笕筇匦岳?,封裝、繼承和多態(tài)里,多態(tài)是最復雜的。
多態(tài)的實現(xiàn)方式分為接口、重寫Override和重載Overload:
接口不用說了。
重寫Override是在父子類之間有相同的方法和參數(shù),是父子類的多態(tài)性。
重載Overload是一個類內(nèi)部有同名方法但是參數(shù)不同,是一個類的多態(tài)性。(重載在編譯期就能確定使用了那個函數(shù),所以不是運行時多態(tài),有些學派因此認為重載不算正宗的多態(tài))
這里面,重寫是一個難點,特別它的多態(tài)性是在運行時表現(xiàn)出來的,容易繞暈,一般來講,重寫多態(tài)是這樣的:
A a=new B();
a叫做引用變量,引用變量指向的具體類型和方法,在編譯時不能確定,是在運行時確定的。
重寫在多態(tài)上的表現(xiàn)就是具體指向哪個重寫方法:
首先,超類(A)中需要定義這個方法。
然后,引用對象(B)中定義了這個方法的最終形態(tài);
多態(tài)重寫有三個必要條件:
1.繼承
2.重寫
3.父類引用指向子類對象
我們先看規(guī)律,再根據(jù)兩個經(jīng)典例題來掌握規(guī)律的用法。
幾個規(guī)律
左右
變量多態(tài)看左邊,
靜態(tài)多態(tài)看左邊,
方法多態(tài)看右邊(左邊的方法表里需要有這個方法)。
優(yōu)先級
假設(shè)有個show(Object obj)函數(shù),那么對于show函數(shù)所在的類及其父類,已經(jīng)參數(shù)Object來說,有固定的優(yōu)先級(JVM虛擬機里的方法表查詢機制,決定了這個優(yōu)先級):
this.show(O)>>super.show(O)>>this.show(super(O))>>super.show(super(O)),這是虛擬機多態(tài)的機制里定義的優(yōu)先級,具體意思是說:
優(yōu)先使用當前類的定義this.show(O)
次優(yōu)先使用父類的定義super.show(O)
第三位使用當前類定義的父類參數(shù)函數(shù)this.show(super(O))
最后使用父類定義的父類參數(shù)函數(shù)super.show(super(O))
例題1
public class A{
void a(){
System.out.print("Aa");
}
void b(){
System.out.print("Ab");
}
}
public class B extends A{
void b(){
System.out.print("Bb");
}
void d(){
System.out.print("Bd");
}
}
private void doTest(){
A a=new B();
a.a(); //Aa 只有A有實現(xiàn),不需要多態(tài)
a.b(); //Bb 在子類B有實現(xiàn),多態(tài)
a.d(); //A的方法表中沒有d,編譯錯誤
B b=(B)a; //可以強轉(zhuǎn)
b.a(); //Aa B沒有實現(xiàn),向父類A中尋找,并找到
b.b(); //Bb B類的方法
b.d(); //Bd B類的方法
}
例題2
class A{
public String show(D obj){
return ("AD");
}
public String show(A obj){
return ("AA");
}
}
class B extends A{
public String show(B obj){
return ("BB");
}
public String show(A obj){
return ("BA");
}
}
class C extends B{}
class D extends B{}
//調(diào)用
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
//其實就是考察從父類/參數(shù)多態(tài)的優(yōu)先級:this.show(O)>>super.show(O)>>this.show(super(O))>>super.show(super(O))
System.out.println(a1.show(b)); // ① AA,因為參數(shù)B是A,優(yōu)先級為this.show(super(O))
//相當于this.show(O)>>super.show(O)>>this.show(super(O)) 這里 >>super.show(super(O))
System.out.println(a1.show(c)); // ② AA,同上
System.out.println(a1.show(d)); // ③ AD,因為A定義了show(D obj),優(yōu)先級為this.show(O)
//相當于this.show(O)這里>>super.show(O)>>this.show(super(O)) >>super.show(super(O))
System.out.println(a2.show(b)); // ④ BA,因為A沒定義show(B obj),只能找到show(A obj),還是優(yōu)先級為this.show(super(O))
//相當于this.show(O)>>super.show(O)>>this.show(super(O)) 這里>>super.show(super(O))
System.out.println(a2.show(c)); // ⑤ AA,同上
System.out.println(a2.show(d)); // ⑥ AD,因為A定義了show(D obj),優(yōu)先級為this.show(O)
//相當于this.show(O)這里>>super.show(O)>>this.show(super(O)) >>super.show(super(O))
System.out.println(b.show(b)); // ⑦ BB,因為B定義了show(B obj),優(yōu)先級為this.show(O)
//相當于this.show(O)這里>>super.show(O)>>this.show(super(O)) >>super.show(super(O))
System.out.println(b.show(c)); // ⑧ BB,因為B定義了show(B obj),優(yōu)先級為this.show(super(O))
//相當于this.show(O)>>super.show(O)>>this.show(super(O)) 這里>>super.show(super(O))
System.out.println(b.show(d)); // ⑨ AD,因為A定義了show(D obj),優(yōu)先級為super.show(O)
//相當于this.show(O)>>super.show(O)這里>>this.show(super(O)) >>super.show(super(O))
總結(jié)
對于A a=new B();這種形式的多態(tài),B是A的子類,那么調(diào)用a.func(D obj)時,需要注意這樣幾個問題:
1.func函數(shù)在A未定義、在B定義。會編譯錯誤,因為a的函數(shù)僅限于A定義過的,B的函數(shù)在a中不能訪問
2.func函數(shù)在A、B都有定義。這時應(yīng)采用B的實現(xiàn)。
3.func函數(shù)在A定義,在B未定義。這時會采用A的實現(xiàn)。
4.func函數(shù)在A、B均未定義。會編譯錯誤。
5.func函數(shù)在A、B都有定義,但是func的參數(shù)沒有D,只有D的父類C,那么需要按照this.show(super(O)) >>super.show(super(O))的順序去選擇函數(shù)。