學(xué)院網(wǎng)站建設(shè)服務(wù)宗旨電商平臺排名
文章目錄
- 多態(tài)
- 多態(tài)實現(xiàn)的條件
- 重寫
- 向上轉(zhuǎn)移和向下轉(zhuǎn)型
- 向上轉(zhuǎn)型
- 向下轉(zhuǎn)型
- 多態(tài)的優(yōu)缺點
- 避免在構(gòu)造方法種調(diào)用重寫的方法
多態(tài)
一種事物,多種形態(tài)。
多態(tài)的概念:去完成某個行為,當不同對象去完成時會產(chǎn)生出不同的狀態(tài)。
多態(tài)實現(xiàn)的條件
1.必須再繼承體系下。
2.子類必須要對父類中的方法進行重寫。
3.通過父類的引用調(diào)用重寫的方法。
當我們發(fā)生向上轉(zhuǎn)型之后,此時通過父類引用只能訪問父類自己的成員,不能訪問到子類特有的成員。
重寫
重寫需要滿足三個條件:
- 方法名稱相同。
- 參數(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+" 正在吃鳥糧!");}
}
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)綁定:也稱為前期綁定(早綁定),即在編譯時,根據(jù)用戶所傳遞實參類型就確定了具體調(diào)用那個方法。典型代表函數(shù)重載。
動態(tài)綁定:也稱為后期綁定(晚綁定),即在編譯時,不能確定方法的行為,需要等到程序運行時,才能夠確定具體調(diào)用那個類的方法。
重寫需要注意:
- private修飾的方法不能被重寫。
- static修飾的方法不能被重寫。
- 子類的訪問修飾限定權(quán)限要大于等于父類的權(quán)限。
private < 默認 < protected < public
- 被final修飾的方法不能被重寫,此時這個方法被稱作密封方法。
向上轉(zhuǎn)移和向下轉(zhuǎn)型
向上轉(zhuǎn)型
實際就是創(chuàng)建一個子類對象,將其當成父類對象來使用。
- 直接賦值
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)點:讓代碼實現(xià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 ,如果該表達式為true,則可以安全轉(zhuǎn)換。
if(animal1 instanceof Dog){//向下轉(zhuǎn)型Dog dog = (Dog)animal1;dog.name = "小黃";dog.wangwang();
}
可以理解為判斷animal1這個引用,是不是引用Dog對象。
多態(tài)的優(yōu)缺點
class Shap{public void draw(){System.out.println("畫圖形!");}
}
class Rect extends Shap{@Overridepublic void draw() {System.out.println("畫矩形!");}
}
class Cycle extends Shap{@Overridepublic void draw() {System.out.println("畫圓!");}
}
class Flower extends Shap{@Overridepublic void draw() {System.out.println("畫一朵花?!");}
}
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("畫圖形!");}
}
class Rect extends Shap{@Overridepublic void draw() {System.out.println("畫矩形!");}
}
class Cycle extends Shap{@Overridepublic void draw() {System.out.println("畫圓!");}
}
class Flower extends Shap{@Overridepublic void draw() {System.out.println("畫一朵花?!");}
}
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)實現(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。
- 可擴展能力更強如果要新增一種新的形狀, 使用多態(tài)的方式代碼改動成本也比較低。
多態(tài)缺陷:代碼的運行效率降低。
- 屬性沒有多態(tài)性:當父類和子類都有同名屬性的時候,通過父類引用,只能引用父類自己的成員屬性。
- 構(gòu)造方法沒有多態(tài)性。
避免在構(gòu)造方法種調(diào)用重寫的方法
下面我們看一段有坑的代碼:
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();}
}
當在父類的構(gòu)造方法當中去調(diào)用父類和子類重寫的方法的時候,此時會調(diào)用子類的。
num為0是因為父類此時還沒有走完,就來到了打印階段。
結(jié)論: “用盡量簡單的方式使對象進入可工作狀態(tài)”, 盡量不要在構(gòu)造器中調(diào)用方法(如果這個方法被子類重寫, 就會觸發(fā)動態(tài)綁定, 但是此時子類對象還沒構(gòu)造完成), 可能會出現(xiàn)一些隱藏的但是又極難發(fā)現(xiàn)的問題。