學(xué)院網(wǎng)站建設(shè)服務(wù)宗旨電商平臺(tái)排名
文章目錄
- 多態(tài)
- 多態(tài)實(shí)現(xiàn)的條件
- 重寫(xiě)
- 向上轉(zhuǎn)移和向下轉(zhuǎn)型
- 向上轉(zhuǎn)型
- 向下轉(zhuǎn)型
- 多態(tài)的優(yōu)缺點(diǎn)
- 避免在構(gòu)造方法種調(diào)用重寫(xiě)的方法
多態(tài)
一種事物,多種形態(tài)。
多態(tài)的概念:去完成某個(gè)行為,當(dāng)不同對(duì)象去完成時(shí)會(huì)產(chǎn)生出不同的狀態(tài)。
多態(tài)實(shí)現(xiàn)的條件
1.必須再繼承體系下。
2.子類必須要對(duì)父類中的方法進(jìn)行重寫(xiě)。
3.通過(guò)父類的引用調(diào)用重寫(xiě)的方法。
當(dāng)我們發(fā)生向上轉(zhuǎn)型之后,此時(shí)通過(guò)父類引用只能訪問(wèn)父類自己的成員,不能訪問(wèn)到子類特有的成員。
重寫(xiě)
重寫(xiě)需要滿足三個(gè)條件:
- 方法名稱相同。
- 參數(shù)列表相同。
- 返回值相同。
class Animal{public String name;public int age;public void eat(){System.out.println(name+" 正在吃飯!");}
}
class Dog extends Animal{public void wangwang(){System.out.println(name+" 正在汪汪叫!");}@Overridepublic void eat(){System.out.println(name+" 正在吃狗糧!");}
}
編譯器可以生成:
class Animal{public String name;public int age;public void eat(){System.out.println(name+" 正在吃飯!");}
}
class Dog extends Animal{public void wangwang(){System.out.println(name+" 正在汪汪叫!");}@Overridepublic void eat(){System.out.println(name+" 正在吃狗糧!");}
}
class Bird extends Animal{public String wing;//翅膀public void fly(){System.out.println(name+" 正在飛!");}@Overridepublic void eat(){System.out.println(name+" 正在吃鳥(niǎo)糧!");}
}
public static void main(String[] args) {Animal animal1 = new Dog();animal1.name = "小黃";animal1.eat();System.out.println("=================");Animal animal2 = new Bird();animal2.name = "圓圓";animal2.eat();
}
靜態(tài)綁定:也稱為前期綁定(早綁定),即在編譯時(shí),根據(jù)用戶所傳遞實(shí)參類型就確定了具體調(diào)用那個(gè)方法。典型代表函數(shù)重載。
動(dòng)態(tài)綁定:也稱為后期綁定(晚綁定),即在編譯時(shí),不能確定方法的行為,需要等到程序運(yùn)行時(shí),才能夠確定具體調(diào)用那個(gè)類的方法。
重寫(xiě)需要注意:
- private修飾的方法不能被重寫(xiě)。
- static修飾的方法不能被重寫(xiě)。
- 子類的訪問(wèn)修飾限定權(quán)限要大于等于父類的權(quán)限。
private < 默認(rèn) < protected < public
- 被final修飾的方法不能被重寫(xiě),此時(shí)這個(gè)方法被稱作密封方法。
向上轉(zhuǎn)移和向下轉(zhuǎn)型
向上轉(zhuǎn)型
實(shí)際就是創(chuàng)建一個(gè)子類對(duì)象,將其當(dāng)成父類對(duì)象來(lái)使用。
- 直接賦值
class Animal{public String name;public int age;public void eat(){System.out.println(name+" 正在吃飯!");}
}
class Dog extends Animal{public void wangwang(){System.out.println(name+" 正在汪汪叫!");}
}
public class Test2 {public static void main1(String[] args) {Dog dog = new Dog();dog.name = "小黃";dog.eat();dog.wangwang();Animal animal = dog;}
}
- 方法傳參
class Animal{public String name;public int age;public void eat(){System.out.println(name+" 正在吃飯!");}
}
class Dog extends Animal{public void wangwang(){System.out.println(name+" 正在汪汪叫!");}
}
public class Test2 {public static void func(Animal animal){}public static void main(String[] args) {Dog dog = new Dog();func(dog);}
}
3.方法返回值
class Animal{public String name;public int age;public void eat(){System.out.println(name+" 正在吃飯!");}
}
class Dog extends Animal{public void wangwang(){System.out.println(name+" 正在汪汪叫!");}
}
public class Test2 {public static Animal func2(){return new Dog();}public static void main(String[] args) {func2();}
}
優(yōu)點(diǎn):讓代碼實(shí)現(xiàn)更簡(jiǎn)單靈活。
缺陷:不能調(diào)用到子類特有的方法。
向下轉(zhuǎn)型
class Animal{public String name;public int age;public void eat(){System.out.println(name+" 正在吃飯!");}
}
class Dog extends Animal{public void wangwang(){System.out.println(name+" 正在汪汪叫!");}
}
public class Test2 {public static void main(String[] args) {Animal animal1 = new Dog();//向下轉(zhuǎn)型Dog dog = (Dog)animal1;dog.name = "小黃";dog.wangwang();}
}
向下轉(zhuǎn)型非常不安全,比如:
解決方法:Java中為了提高向下轉(zhuǎn)型的安全性,引入了 instanceof ,如果該表達(dá)式為true,則可以安全轉(zhuǎn)換。
if(animal1 instanceof Dog){//向下轉(zhuǎn)型Dog dog = (Dog)animal1;dog.name = "小黃";dog.wangwang();
}
可以理解為判斷animal1這個(gè)引用,是不是引用Dog對(duì)象。
多態(tài)的優(yōu)缺點(diǎn)
class Shap{public void draw(){System.out.println("畫(huà)圖形!");}
}
class Rect extends Shap{@Overridepublic void draw() {System.out.println("畫(huà)矩形!");}
}
class Cycle extends Shap{@Overridepublic void draw() {System.out.println("畫(huà)圓!");}
}
class Flower extends Shap{@Overridepublic void draw() {System.out.println("畫(huà)一朵花?!");}
}
public class Test3 {public static void drawMap(Shap shap){shap.draw();}public static void main(String[] args) {Rect rect = new Rect();Cycle cycle = new Cycle();drawMap(rect);drawMap(cycle);drawMap(new Flower());}
}
class Shap{public void draw(){System.out.println("畫(huà)圖形!");}
}
class Rect extends Shap{@Overridepublic void draw() {System.out.println("畫(huà)矩形!");}
}
class Cycle extends Shap{@Overridepublic void draw() {System.out.println("畫(huà)圓!");}
}
class Flower extends Shap{@Overridepublic void draw() {System.out.println("畫(huà)一朵花?!");}
}
public class Test3 {public static void drawMap2(){Rect rect = new Rect();Cycle cycle = new Cycle();Flower flower = new Flower();//c r c r fString[] shapes = {"cycle", "rect", "cycle", "rect", "flower"};for (String shape : shapes) {if (shape.equals("cycle")) {cycle.draw();} else if (shape.equals("rect")) {rect.draw();} else if (shape.equals("flower")) {flower.draw();}}}public static void main(String[] args) {drawMap2();}
}
多態(tài)實(shí)現(xiàn):
public static void drawMap3(){Rect rect = new Rect();Cycle cycle = new Cycle();Flower flower = new Flower();Shap [] shaps = {cycle,rect,cycle,rect,flower};for(Shap shap:shaps){shap.draw();}
}
多態(tài)好處:
- 能夠降低代碼的 “圈復(fù)雜度”, 避免使用大量的 if - else。
- 可擴(kuò)展能力更強(qiáng)如果要新增一種新的形狀, 使用多態(tài)的方式代碼改動(dòng)成本也比較低。
多態(tài)缺陷:代碼的運(yùn)行效率降低。
- 屬性沒(méi)有多態(tài)性:當(dāng)父類和子類都有同名屬性的時(shí)候,通過(guò)父類引用,只能引用父類自己的成員屬性。
- 構(gòu)造方法沒(méi)有多態(tài)性。
避免在構(gòu)造方法種調(diào)用重寫(xiě)的方法
下面我們看一段有坑的代碼:
class B {public B() {
// do nothingfunc();}public void func() {System.out.println("B.func()");}
}
class D extends B {private int num = 1;@Overridepublic void func() {System.out.println("D.func() " + num);}
}
public class Test4 {public static void main(String[] args) {D d = new D();}
}
當(dāng)在父類的構(gòu)造方法當(dāng)中去調(diào)用父類和子類重寫(xiě)的方法的時(shí)候,此時(shí)會(huì)調(diào)用子類的。
num為0是因?yàn)楦割惔藭r(shí)還沒(méi)有走完,就來(lái)到了打印階段。
結(jié)論: “用盡量簡(jiǎn)單的方式使對(duì)象進(jìn)入可工作狀態(tài)”, 盡量不要在構(gòu)造器中調(diào)用方法(如果這個(gè)方法被子類重寫(xiě), 就會(huì)觸發(fā)動(dòng)態(tài)綁定, 但是此時(shí)子類對(duì)象還沒(méi)構(gòu)造完成), 可能會(huì)出現(xiàn)一些隱藏的但是又極難發(fā)現(xiàn)的問(wèn)題。