目錄
- 1、多態的概念
- 2、多態的條件
- 3、向上轉型
- 3.1 概念
- 3.2 使用場景
- 4、向下轉型
- 5、多態的優缺點
1、多態的概念
多態,通俗來講就是多種形態,即對于同樣的行為,不同的對象去完成會產生不同的狀態。比如動物都會吃東西,小狗和小貓都是動物,但是小狗是吃狗糧,而小貓是吃貓糧。
2、多態的條件
在 Java 中實現多態需要滿足下述條件,缺一不可:
- 必須在繼承體系下。
- 子類對基類的方法實現重寫(即方法原型相同,但實現體不同)。
- 通過基類的引用調用重寫的方法。
多態的體現:在代碼運行時,當傳遞不同類的對象時,會調用對應類中的方法。
舉例說明:Animal 類是父類,Dog 類和 Cat 類是子類,繼承自 Animal 類,同時 Dog 類和 Cat 類對 Animal 類的方法進行了重寫。
// 父類
public class Animal {protected String name;protected int age;public Animal(String name, int age) {this.name = name;this.age = age;}public void eat(){System.out.println(name + "在吃飯");}public void bark(){System.out.println(name + "在大叫");}
}// Dog 類:繼承自 Animal 類
// 1. 在繼承體系中
public class Dog extends Animal{protected String color;public Dog(String name, int age, String color) {super(name, age);this.color = color;}// 2. 對父類方法進行重寫@Overridepublic void eat() {System.out.println(name + "在吃狗糧");}@Overridepublic void bark() {System.out.println(name + "汪汪汪~");}public void sleep(){System.out.println(name + "在睡覺");}
}// Cat 類:繼承自 Animal 類
// 1. 在繼承體系下
public class Cat extends Animal {protected String temper;public Cat(String name, int age, String temper) {super(name, age);this.temper = temper;}// 2. 對父類方法進行重寫@Overridepublic void eat() {System.out.println(name + "在吃貓糧");}@Overridepublic void bark() {System.out.println(name + "喵喵喵~");}public void drink(){System.out.println(name + "在喝水");}
}
根據上述類,利用 Animal 類的引用調用被重寫的方法從而實現多態。
public class Test {public static void method(Animal animal){// 3. 通過基類的引用調用被重寫的方法// 在 method() 方法中利用 Animal 對象的引用調用被重寫的方法// 在程序的編譯階段并不知道會調用哪個子類的對象所對應的方法// 只有在運行階段給 method() 方法傳參時才知道。animal.eat();animal.bark();}public static void main(String[] args) {Dog dog = new Dog("毛毛", 5, "白色");method(dog);Cat cat = new Cat("小七", 1, "乖巧");method(cat);}
}
運行結果:
由上述代碼可知,雖然在 main 方法中調用的是同一個 method() 方法,但是運行的結果卻不同。這是因為 Animal 類是 Dog 類和 Cat 類的基類,基類可以引用不同子類的對象,因此傳遞給形參 animal的值會出現不同,當傳遞的是 Dog 類的對象時,會調用 Dog 類中的方法,當傳遞的是 Cat 類的對象時,會調用 Cat 類中的方法。
當程序員在編寫 method() 方法時并不知道也不關心形參 animal 指的是 Cat 類還是 Dog 類的對象,只有當代碼運行起來,實參傳遞給形參值的時候才知道。形參 animal 調用方法會有不同的表現,這種行為就稱作多態。
3、向上轉型
3.1 概念
向上轉型,實際上是創建一個子類對象,當作父類對象來使用。
Animal animal = new Dog(“毛毛”, 5, “白色”);
animal 是父類類型,可以引用子類對象,因為狗和貓都是動物,這是從小范圍到大范圍的轉換,是安全的。但是向上轉型之后,無法通過父類的引用調用子類新增的成員方法。
3.2 使用場景
向上轉型有以下三種使用場景:
- 直接賦值:子類對象賦值給父類對象。
Animal animal = new Dog("毛毛", 5, "白色");
- 方法傳參:形參為父類型引用,可以接收任意子類的對象。
public class Test {// 將 Dog 類和 Cat 類對象的引用傳參給 Animal 類的引用public static void method(Animal animal){animal.eat();animal.bark();}public static void main(String[] args) {Dog dog = new Dog("毛毛", 5, "白色");method(dog);Cat cat = new Cat("小七", 1, "乖巧");method(cat);}
}
- 方法返回:方法返回類型是父類類型,可以返回任意子類對象。
public Animal buyCat(){// 創建 cat 對象并返回Cat cat = new Cat("小七", 1, "乖巧");return cat;}
4、向下轉型
將子類對象轉換為父類時,會無法調用子類中特有的方法,但是有時候需要調用,那么此時將父類引用還原為子類對象即可,即向下轉換。
public static void main(String[] args) {Animal animal = new Dog("毛毛", 5, "白色");// 將 Animal 類型對象強轉為 Dog 類型,此時可以調用 sleep() 方法Dog dog = (Dog) animal;dog.sleep();}
但是向下轉型很容易出現問題。
Java 中為了提高向下轉型的安全性,引入了 instanceof。
instanceof 類名N:實際引用的是否為 N 類的對象,如果是返回true,否則返回false
如果該表達式為真,則可以安全轉換,否則不能進行安全轉換。
public static void main(String[] args) {Dog dog = new Dog("毛毛", 5, "白色");Cat cat = new Cat("小七", 1, "乖巧");Animal animal = cat;animal = dog; // 此時 animal 實際指向的是 Dog 類的對象if(animal instanceof Cat){cat = (Cat)animal;cat.drink();}if(animal instanceof Dog){dog = (Dog)animal;dog.sleep();}}
運行結果:
由上述結果可知,由于 animal 實際指向的是 Dog 類的對象,因此執行第二個 if 語句塊,將 animal 強轉為 Dog 類型對象,此時就可以調用 Dog 類中新增的成員方法。
5、多態的優缺點
【優點】
- 降低代碼的“圈復雜度”,即避免大量使用 if-else。
- 可擴展能力更強。
【缺點】
- 代碼的運行效率降低。
- 屬性沒有多態性:當子類和父類有同名屬性時,通過父類引用,只能引用父類自己的成員屬性。
- 構造方法沒有多態性。