多態(tài)
Java面向?qū)ο缶幊逃腥筇匦裕悍庋b,繼承和多態(tài)
封裝隱藏類的內(nèi)部具體實現(xiàn)機制躬存,保護數(shù)據(jù)张惹,對外界隱藏內(nèi)部細節(jié),只向外部提供它所允許訪問的方法
繼承是為了復(fù)用代碼和實現(xiàn)向上轉(zhuǎn)型岭洲,當然繼承也是為多態(tài)做準備宛逗。
多態(tài)可以說是Java面向?qū)ο蟮木A所在。
什么是多態(tài)
多態(tài)是指允許不同子類型的對象對同一消息做出不同的響應(yīng)盾剩,簡單來講雷激,就是用同樣的對象調(diào)用同樣的方法但是卻做了不同的事情。也可以理解為一個事物的多種表現(xiàn)形態(tài)告私。
多態(tài)性分為編譯時的多態(tài)性和運行時的多態(tài)性屎暇。例如:
方法重載:實現(xiàn)的是編譯時的多態(tài)性
方法重寫:實現(xiàn)的是運行是的多態(tài)性
子類對象的多態(tài)性,這個是Java多態(tài)性中最常用的事驻粟。
實現(xiàn)多態(tài)的條件
1.方法重寫根悼,也就是說要有繼承吧,只有有了繼承蜀撑,子類重寫了父類已有的或抽象的方法
2.對象造型挤巡,也就是說要有父類的引用指向子類對象
只有這樣,同樣的引用調(diào)用同樣的方法就會作出不同的響應(yīng)屯掖,簡單來講如下代碼所示:
父類Person有如下方法:
public void walk(){
System.out.println("人走路");
}
public void eat(){
System.out.println("人吃飯");
}
如果子類Man類沒有重寫這兩個方法,那么我們做如下的事情:
Person man = new Man();
man.walk();
輸出結(jié)果:
人走路
綜上所述:父類引用man指向的是子類對象襟衰,這個就是子類對象的多態(tài)性(也叫向上轉(zhuǎn)型)贴铜,man可以調(diào)用父類的方法,前提是子類沒有重寫父類方法瀑晒。
如果子類Man類重寫了父類方法
public void walk(){
System.out.println("男人應(yīng)該挺拔的走路");
}
public void eat(){
System.out.println("男人應(yīng)該多吃肉");
}
同樣的調(diào)用:
Person man = new Man();
man.walk();
結(jié)果就是:
男人應(yīng)該挺拔的走路
綜上所述:子類對象重寫了父類方法绍坝,那么man調(diào)用父類方法,執(zhí)行的就是子類的方法苔悦。這個也虛擬方法調(diào)用轩褐,說到這里你應(yīng)該可以猜到,什么是多態(tài)了吧玖详,就是同樣的父類對象應(yīng)用把介,指向不同的子類對象勤讽,就會作出不同的響應(yīng),例如子類Woman類也重寫了父類的方法:
public void walk(){
System.out.println("女人應(yīng)該溫柔的走路");
}
public void eat(){
System.out.println("女人應(yīng)該少吃肉多吃水果蔬菜");
}
調(diào)用方法:
Person man = new Man();
Person woman = new Woman();
man.walk();
woman.walk();
結(jié)果為:
男人應(yīng)該挺拔的走路
女人應(yīng)該溫柔的走路
綜上所述:應(yīng)該是很清晰了什么是子類對象的多態(tài)性拗踢,就是你相同的父類引用脚牍,不同的子類對象,就會響應(yīng)對應(yīng)的子類對象的方法巢墅。
方法重載和方法重寫
方法重載和方法重寫兩者都是實現(xiàn)多態(tài)的方式诸狭,區(qū)別在于方法重載實現(xiàn)的是編譯時的多態(tài),方法重寫實現(xiàn)的是運行時的多態(tài)君纫,重載發(fā)生在同一個類中驯遇,同名的方法有不同的參數(shù)列表。
注意:方法的重載與返回值無關(guān)蓄髓,簡稱兩同一不同叉庐,同一個類,同一個方法双吆,不同的參數(shù)列表
方法的重寫發(fā)生在子類和父類之間眨唬,重寫要求子類方法返回值,方法名好乐,參數(shù)列表與父類爆出一致匾竿,權(quán)限修飾符大于父類,同時要同為static或同為非static蔚万。
注意:構(gòu)造器不能被繼承岭妖,所以不能被重寫,但是卻可以被重載
多態(tài)的使用例子
例如在父類Person類中有如下方法:
public void show(Person person){
System.out.println("這是父類show方法");
}
子類Man類重寫了子類方法:
public void show(Person person){
System.out.println("這是子類show方法");
}
如果實例化Man對象反璃,調(diào)用man的show(Person person)方法昵慌,就應(yīng)該傳入Person對象,這個時候就可以傳入父類對象的引用淮蜈。
Person man = new Man();
man.show(man);
父類引用指向不同的子類對象斋攀,作出不同的響應(yīng)。
多態(tài)經(jīng)典案例
摘自http://blog.csdn.net/thinkGhoster/archive/2008/04/19/2307001.aspx
public class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
public class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
public class C extends B{
}
public class D extends B{
}
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}
輸出結(jié)果為:
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D
結(jié)果分析如下:
System.out.println("1--" + a1.show(b)); //a1是A的引用指向是A對象梧田,故調(diào)用A中的show方法淳蔼,傳入的是b,b指向的是B對象裁眯,因為B繼承與A,故傳入的也可認為是A鹉梨,結(jié)果為A and A
System.out.println("2--" + a1.show(c)); //c指向C對象,C繼承B,B繼承A,相當于傳入A穿稳,結(jié)果為A and A
System.out.println("3--" + a1.show(d)); //d指向D對象存皂,在A中有傳入D對象的方法,結(jié)果為 A and D
System.out.println("4--" + a2.show(b)); //a2是父類引用逢艘,指向子類對象旦袋,按理說調(diào)用show方法會執(zhí)行子類B的show方法骤菠,傳入的是b,b指向的是B對象,
//但是B中的show(B)是子類特有的方法,故不能被調(diào)用猜憎,傳入的是B,B繼承與A娩怎,相當于傳入A,B類重寫了show(B)方法,結(jié)果為B and A
System.out.println("5--" + a2.show(c)); //傳入c,執(zhí)行B中show(C)的方法胰柑,沒有截亦,C繼承B,執(zhí)行B中show(B),但是這是B中特有方法,不能被調(diào)用柬讨,
//B繼承A,調(diào)用B中show(A),結(jié)果B and A
System.out.println("6--" + a2.show(d)); //傳入D,執(zhí)行B中show(D)方法崩瓤,沒有,但是A中有就會執(zhí)行父類show(D)方法踩官,所以結(jié)果為:A and D
System.out.println("7--" + b.show(b)); //b指向B,傳入B, 結(jié)果為B and B
System.out.println("8--" + b.show(c)); //傳入c,執(zhí)行B中show(C),沒有却桶,C繼承B,執(zhí)行B中show(B),結(jié)果為:B and B
System.out.println("9--" + b.show(d)); //傳入d,執(zhí)行B中show(D)方法,沒有蔗牡,當時B繼承A,是存在A中show(D)的方法颖系,結(jié)果為 A and D
案例總結(jié)
對于a2.show(c)來講,a2是A的應(yīng)用,故先去A中找show(C)方法(this.show(O)),A中沒有辩越,按理應(yīng)該去A的父類中找(super.show(O))嘁扼,但是A沒有父類,故只能在A中找show(c的父類)方法(this.show(super))黔攒,c的父類有B和A,A中找到show(A)的方法趁啸,但是B重寫了該方法,故執(zhí)行子類的方法督惰,所以結(jié)果為B and A不傅。找的順序是this.show(O)、super.show(O)赏胚、this.show((super)O)访娶、super.show((super)O)。