我們知道蜒灰,面向?qū)ο笕筇匦岳锵阴澹庋b、繼承和多態(tài)里强窖,多態(tài)是最復(fù)雜的凸椿。
多態(tài)的實(shí)現(xiàn)方式分為接口、重寫(xiě)Override和重載Overload:
接口不用說(shuō)了翅溺。
重寫(xiě)Override是在父子類(lèi)之間有相同的方法和參數(shù)脑漫,是父子類(lèi)的多態(tài)性。
重載Overload是一個(gè)類(lèi)內(nèi)部有同名方法但是參數(shù)不同咙崎,是一個(gè)類(lèi)的多態(tài)性优幸。(重載在編譯期就能確定使用了那個(gè)函數(shù),所以不是運(yùn)行時(shí)多態(tài)褪猛,有些學(xué)派因此認(rèn)為重載不算正宗的多態(tài))
這里面网杆,重寫(xiě)是一個(gè)難點(diǎn),特別它的多態(tài)性是在運(yùn)行時(shí)表現(xiàn)出來(lái)的,容易繞暈碳却,一般來(lái)講队秩,重寫(xiě)多態(tài)是這樣的:
A a=new B();
a叫做引用變量,引用變量指向的具體類(lèi)型和方法昼浦,在編譯時(shí)不能確定馍资,是在運(yùn)行時(shí)確定的。
重寫(xiě)在多態(tài)上的表現(xiàn)就是具體指向哪個(gè)重寫(xiě)方法:
首先关噪,超類(lèi)(A)中需要定義這個(gè)方法迷帜。
然后,引用對(duì)象(B)中定義了這個(gè)方法的最終形態(tài)色洞;
多態(tài)重寫(xiě)有三個(gè)必要條件:
1.繼承
2.重寫(xiě)
3.父類(lèi)引用指向子類(lèi)對(duì)象
我們先看規(guī)律,再根據(jù)兩個(gè)經(jīng)典例題來(lái)掌握規(guī)律的用法冠胯。
幾個(gè)規(guī)律
左右
變量多態(tài)看左邊火诸,
靜態(tài)多態(tài)看左邊,
方法多態(tài)看右邊(左邊的方法表里需要有這個(gè)方法)荠察。
優(yōu)先級(jí)
假設(shè)有個(gè)show(Object obj)函數(shù)置蜀,那么對(duì)于show函數(shù)所在的類(lèi)及其父類(lèi),已經(jīng)參數(shù)Object來(lái)說(shuō)悉盆,有固定的優(yōu)先級(jí)(JVM虛擬機(jī)里的方法表查詢(xún)機(jī)制盯荤,決定了這個(gè)優(yōu)先級(jí)):
this.show(O)>>super.show(O)>>this.show(super(O))>>super.show(super(O)),這是虛擬機(jī)多態(tài)的機(jī)制里定義的優(yōu)先級(jí)焕盟,具體意思是說(shuō):
優(yōu)先使用當(dāng)前類(lèi)的定義this.show(O)
次優(yōu)先使用父類(lèi)的定義super.show(O)
第三位使用當(dāng)前類(lèi)定義的父類(lèi)參數(shù)函數(shù)this.show(super(O))
最后使用父類(lèi)定義的父類(lèi)參數(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有實(shí)現(xiàn)秋秤,不需要多態(tài)
a.b(); //Bb 在子類(lèi)B有實(shí)現(xiàn),多態(tài)
a.d(); //A的方法表中沒(méi)有d脚翘,編譯錯(cuò)誤
B b=(B)a; //可以強(qiáng)轉(zhuǎn)
b.a(); //Aa B沒(méi)有實(shí)現(xiàn)灼卢,向父類(lèi)A中尋找,并找到
b.b(); //Bb B類(lèi)的方法
b.d(); //Bd B類(lèi)的方法
}
例題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í)就是考察從父類(lèi)/參數(shù)多態(tài)的優(yōu)先級(jí):this.show(O)>>super.show(O)>>this.show(super(O))>>super.show(super(O))
System.out.println(a1.show(b)); // ① AA来农,因?yàn)閰?shù)B是A鞋真,優(yōu)先級(jí)為this.show(super(O))
//相當(dāng)于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沃于,因?yàn)锳定義了show(D obj)涩咖,優(yōu)先級(jí)為this.show(O)
//相當(dāng)于this.show(O)這里>>super.show(O)>>this.show(super(O)) >>super.show(super(O))
System.out.println(a2.show(b)); // ④ BA,因?yàn)锳沒(méi)定義show(B obj)繁莹,只能找到show(A obj)檩互,還是優(yōu)先級(jí)為this.show(super(O))
//相當(dāng)于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咨演,因?yàn)锳定義了show(D obj)盾似,優(yōu)先級(jí)為this.show(O)
//相當(dāng)于this.show(O)這里>>super.show(O)>>this.show(super(O)) >>super.show(super(O))
System.out.println(b.show(b)); // ⑦ BB,因?yàn)锽定義了show(B obj),優(yōu)先級(jí)為this.show(O)
//相當(dāng)于this.show(O)這里>>super.show(O)>>this.show(super(O)) >>super.show(super(O))
System.out.println(b.show(c)); // ⑧ BB零院,因?yàn)锽定義了show(B obj)溉跃,優(yōu)先級(jí)為this.show(super(O))
//相當(dāng)于this.show(O)>>super.show(O)>>this.show(super(O)) 這里>>super.show(super(O))
System.out.println(b.show(d)); // ⑨ AD,因?yàn)锳定義了show(D obj)告抄,優(yōu)先級(jí)為super.show(O)
//相當(dāng)于this.show(O)>>super.show(O)這里>>this.show(super(O)) >>super.show(super(O))
總結(jié)
對(duì)于A(yíng) a=new B();這種形式的多態(tài)撰茎,B是A的子類(lèi),那么調(diào)用a.func(D obj)時(shí)打洼,需要注意這樣幾個(gè)問(wèn)題:
1.func函數(shù)在A(yíng)未定義龄糊、在B定義。會(huì)編譯錯(cuò)誤募疮,因?yàn)閍的函數(shù)僅限于A(yíng)定義過(guò)的炫惩,B的函數(shù)在a中不能訪(fǎng)問(wèn)
2.func函數(shù)在A(yíng)、B都有定義阿浓。這時(shí)應(yīng)采用B的實(shí)現(xiàn)他嚷。
3.func函數(shù)在A(yíng)定義,在B未定義芭毙。這時(shí)會(huì)采用A的實(shí)現(xiàn)筋蓖。
4.func函數(shù)在A(yíng)、B均未定義退敦。會(huì)編譯錯(cuò)誤粘咖。
5.func函數(shù)在A(yíng)、B都有定義侈百,但是func的參數(shù)沒(méi)有D瓮下,只有D的父類(lèi)C,那么需要按照this.show(super(O)) >>super.show(super(O))的順序去選擇函數(shù)钝域。