多態(tài)簡(jiǎn)介
多態(tài)就是事物存在的多種形態(tài),比如你在大街上看見一只藏獒,你可以說這只藏獒真兇猛蹋嵌,也可以說這只狗真兇猛,還可以說這個(gè)動(dòng)物真兇猛葫隙,以上三種說法其實(shí)都是指的這只藏獒栽烂。
在Java里面,也是存在多態(tài)的,只要全部符合下面這三種情況腺办,就是多態(tài)
????????有繼承
????????有方法重寫
????????有父類引用指向子類對(duì)象
例如下面代碼就構(gòu)成多態(tài)焰手、
定義一個(gè)Animal類
public class Animal{
? ? int num = 10;
? ? publicvoideat(){
? ? ? ? System.out.println("動(dòng)物在吃!");
? ? }
}
定義一個(gè)Cat類繼承Animal
public class Cat extends Animal{
? ? int num = 20;
? ? //重寫? ? publicvoideat(){
? ? ? ? System.out.println("貓吃貓糧");
? ? }
? ? //Cat特有的方法.? ??
????public void move(){
? ? ? ? System.out.println("貓走路很輕盈怀喉!");
? ? }
}
定義一個(gè)Dog類繼承Animal
public class ????DogextendsAnimal{
? ? //重寫? ??
public void eat(){
? ? ? ? System.out.println("狗啃骨頭书妻!");
? ? }
}
上面的三個(gè)類里面已經(jīng)有繼承和方法重寫了,那么父類引用指向子類對(duì)象是什么磺送?請(qǐng)看下面這段代碼:
定義一個(gè)測(cè)試類
public class AnimalTest01{
? ? publicstaticvoidmain(String[] args){
? ? ? ? Cat c1 = new Cat();
? ? ? ? c1.eat();
? ? ? ? Animal a1 = new Cat();//父類引用指向子類對(duì)象? ? ? ??
????????a1.eat();
? ? ? ? System.out.println(a1.num);//因?yàn)槌蓡T變量不存在重寫驻子,所以結(jié)果是10? ? }
}
靜態(tài)綁定和動(dòng)態(tài)綁定
上面代碼中,a1是Animal類型的一個(gè)引用估灿,指向的是其子類Cat的對(duì)象崇呵,這個(gè)就叫做父類引用指向子類對(duì)象。程序在編譯的時(shí)候a1被看做Animal類型馅袁,所以a1.eat()綁定的是Animal類中的eat()方法域慷,這叫做靜態(tài)綁定,程序運(yùn)行時(shí)汗销,a1指向的是堆中的Cat對(duì)象犹褒,而在Cat中對(duì)eat()方法進(jìn)行了重寫,所以在運(yùn)行階段綁定的是Cat中的eat()方法弛针,這叫做動(dòng)態(tài)綁定叠骑。
強(qiáng)制類型轉(zhuǎn)換
上面代碼中子類向父類型進(jìn)行轉(zhuǎn)換,是自動(dòng)類型轉(zhuǎn)換削茁,也叫做向上轉(zhuǎn)型宙枷。還有一種情況是父類向子類型轉(zhuǎn)換,是強(qiáng)制類型轉(zhuǎn)換茧跋,也叫向下轉(zhuǎn)型慰丛。下面的代碼演示了強(qiáng)制類型轉(zhuǎn)換
public class AnimalTest01{
? ? publicstaticvoidmain(String[] args){
? ? ? ? Animal a1 = new Cat();//父類引用指向子類對(duì)象? ? ? ??
//如果要是想執(zhí)行Cat里面的move方法該怎么辦?? ? ??
? //只能強(qiáng)制類型轉(zhuǎn)換,需要加強(qiáng)制類型轉(zhuǎn)換符? ? ? ?
?????Cat c1 = (Cat)a1;
? ? ? ? c1.move();
? ? ? ? Animal a2 = new Dog(); //向上轉(zhuǎn)型.? ? ??
? //強(qiáng)制類型轉(zhuǎn)換? ? ? ??
//Cat c2 = (Cat)a2; //會(huì)報(bào)錯(cuò) java.lang.ClassCastException? ?
?}
}
instanceof關(guān)鍵字
上面的代碼里面將一個(gè)指向Dog對(duì)象的Animal引用a2進(jìn)行強(qiáng)制轉(zhuǎn)換成Cat類型時(shí)報(bào)出了ClassCastException類轉(zhuǎn)型錯(cuò)誤瘾杭,開發(fā)中要是想避免這種錯(cuò)誤需要使用instanceof來判斷一下诅病。
public classAnimalTest01{
? ? publicstaticvoidmain(String[] args){
? ? ? ? Animal a1 = new Cat();//父類引用指向子類對(duì)象? ? ? ??
//如果要是想執(zhí)行Cat里面的move方法該怎么辦?? ? ? ??
//只能強(qiáng)制類型轉(zhuǎn)換,需要加強(qiáng)制類型轉(zhuǎn)換符? ? ? ? Cat c1 = (Cat)a1;
? ? ? ? c1.move();
? ? ? ? Animal a2 = new Dog(); //向上轉(zhuǎn)型.? ? ? ??
//進(jìn)行強(qiáng)制類型轉(zhuǎn)換時(shí)粥烁,需要先使用instanceof進(jìn)行判斷贤笆,避免ClassCastException? ? ? ??
if(a2 instanceof Cat){
? ? ? ? ? ? //強(qiáng)制類型轉(zhuǎn)換? ? ? ? ? ??
????????????Cat c2 = (Cat)a2;
? ? ? ? }
? ? }? ?
}
多態(tài)的優(yōu)點(diǎn)
????????提高了程序的擴(kuò)展性
????????降低了代碼之間的耦合
請(qǐng)看下面示例:
新建一個(gè)Car類
class Car{
? ? publicvoidrun(){
? ? ? ? System.out.println("汽車在跑");
? ? }
}
創(chuàng)建一個(gè)Benz類繼承Car
classBenzextendsCar{
? ? publicvoidrun(){
? ? ? ? System.out.println("奔馳汽車在跑");
? ? }
}
創(chuàng)建一個(gè)BMW類繼承Car
classBMWextendsCar{
? ? publicvoidrun(){
? ? ? ? System.out.println("寶馬汽車在跑");
? ? }
}
創(chuàng)建一個(gè)Person類用來開車
class Person {
? ? /*
? ? public void drive(Benz bc){
? ? ? ? bc.run();
? ? }
? ? 奔馳汽車壞了,再重新創(chuàng)建一個(gè)開寶馬汽車的方法
? ? public void drive(BMW bm){
? ? ? ? bm.run();
? ? }
? ? */? ??
//上面代碼擴(kuò)展性太差页徐,每新增加一種品牌的汽車就需要再寫一個(gè)方法? ? //將參數(shù)修改為Car類型苏潜,這樣不論增加什么樣的品牌汽車,都可以調(diào)用這個(gè)方法? ?
?publicvoiddrive(Car c){
? ? ? ? c.run();
? ? }
}
創(chuàng)建一個(gè)測(cè)試類
public class Test01 {
? ? publicstaticvoidmain(String[] args){
? ? ? ? Person james = new Person();
? ? ? ? Benz bc = new Benz();
? ? ? ? james.drive(bc);
? ? ? ? BMW bm = new BMW();? ?
? ? ? ? james.drive(bm);
? ? }
}
在工作當(dāng)中盡量面向抽象編程变勇,不要面向具體編程恤左。