内容:
1、多态概述
2、多态代碼展現
3、多态調用注意事項
4、多态的好處與弊端
5、向上向下類型轉換
6、綜合案例
面向對象三大特性:封裝(安全性)、繼承(拓展性)、多态(靈活性)
多态是繼封裝、繼承之後,面向對象的第三大特性,廣義的多态是指對象的多态,一個對象的多種狀态
現實事物經常會展現出多種形态,比如:
- 一隻狗是狗,是動物,是生物
- 一個人是人,是動物,是生物
- 你 在學校裡是學生,在家裡便是兒子
狹義的多态就是指程式中定義的引用變量所指向的具體類型和通過該引用變量發出的方法調用
在程式設計時并不确定,而是在程式運作期間才确定,即一個引用變量倒底會指向哪個類的執行個體對象,
該引用變量發出的方法調用到底是哪個類中實作的方法,必須在由程式運作期間才能決定。因為
在程式運作時才确定具體的類,這樣,不用修改源程式代碼,就可以讓引用變量綁定到各種不同的
類實作上,進而導緻該引用調用的具體方法随之改變,即不修改程式代碼就可以改變程式運作時所
綁定的具體代碼,讓程式可以選擇多個運作狀态,這就是多态性。
Java多态的前提:
- 必須有子父類關系(繼承)
- 必須有方法的重寫
多态在Java中的表現形式:
Java中多态展現在一個子類對象(實作類對象)既可以給這個子類(實作類對象)引用變量指派,
又可以給這個子類(實作類對象)的父類(接口)變量指派
如Student類可以為Person類的子類,那麼一個Student對象既可以指派給一個Student類型的引用,
也可以指派給一個Person類型的引用
具體格式如下:
- 父類類型 變量名 = new 子類類型();
- 變量名.方法名();
父類引用指向子類對象就是多态的定義格式。同一個父類的方法會被不同的子類重寫為各自的具體實作。
而在調用方法時,調用的為各個子類重寫後的方法,此時,雖然該變量指向的是子類對象,但表現為
一個父類的形态,可以調用一切父類的方法,子類特有的方法将不能調用
多态執行個體:
1 class Animal {
2 int age = 100;
3 public void eat(){
4 System.out.println("動物在吃飯");
5 }
6 }
7
8 class Dog extends Animal{
9 int age = 1000;
10
11 public void eat() {
12 // TODO Auto-generated method stub
13 System.out.println("狗在吃飯");
14 }
15
16 }
17
18
19 public class DuoTaiDemo {
20 public static void main(String[] args) {
21 // 使用多态建立一個狗
22 Animal an = new Dog();
23 an.eat(); // 狗在吃飯
24 }
25 }
- 成員變量編譯看父類中是否存在,不存在編譯失敗
- 成員變量運作父類中的變量
- 成員方法編譯看父類中是否存在,不存在編譯失敗
- 成員方法運作子類重寫的方法
總結:多态使用變量,編譯運作都看父類,而多态使用方法,編譯看父類,運作看子類
執行個體如下:
1 class Animal {
2 int age = 100;
3 public void eat(){
4 System.out.println("動物在吃飯");
5 }
6 }
7
8 class Dog extends Animal{
9 int age = 1000;
10
11 public void eat() {
12 // TODO Auto-generated method stub
13 System.out.println("狗在吃飯");
14 }
15
16 }
17
18
19 public class DuoTaiDemo {
20 public static void main(String[] args) {
21 // 使用多态建立一個狗
22 Animal an = new Dog();
23 an.eat(); // 狗在吃飯 => 子類 => 看右邊
24 System.out.println(an.age); // 100 => 父類 => 看左邊
25 }
26 }
另外靜态成員和多态無關!
1 /*
2 * 多态調用:
3 * 非靜态成員變量:
4 * 編譯看父類
5 * 運作看父類
6 *
7 * 非靜态成員方法:XXXXXXX 為什麼?很簡單
8 * 編譯看父類
9 * 運作看子類
10
11 靜态成員變量:
12 * 編譯看父類
13 * 運作看父類
14 * 靜态成員方法:
15 * 編譯看父類
16 * 運作看父類
17
18 *
19 * 一句話解釋 :我們說的多态是指對象的多态性: 靜态不屬于對象,屬于類
20 */
21 public class DuoTaiDemo {
22 public static void main(String[] args) {
23 Fu f = new Zi();
24 //System.out.println(f.a);
25 f.show();
26 }
27 }
28 public class Fu {
29 static int a = 1;
30
31 public static void show(){
32 System.out.println("靜态方法父類");
33 }
34 }
35 public class Zi extends Fu{
36 static int a = 2;
37 public static void show(){
38 System.out.println("靜态方法子類");
39 }
40 }
多态:當變量名指向不同的子類對象時,由于每個子類重寫父類方法的内容不同,是以會調用不同的方法
在Boss類中,有叫員工去工作的方法,當該方法的參數定義為接口時,可以傳入任意的子類對象。
相比定義多個子類參數,定義多個方法,這樣大大提高了代碼複用性與擴充性:
1 class Boss{
2 public void goToWork(Empolyee e){
3 e.work();
4 }
5 }
而多态也有缺點,執行個體如下:
1 class Animal {
2 int age = 100;
3 public void eat(){
4 System.out.println("動物在吃飯");
5 }
6 }
7
8 class Dog extends Animal{
9 int age = 1000;
10
11 public void eat() {
12 // TODO Auto-generated method stub
13 System.out.println("狗在吃飯");
14 }
15
16 public void lookHome(){
17 System.out.println("狗在看門");
18 }
19
20 }
21
22
23 public class DuoTaiDemo {
24 public static void main(String[] args) {
25 // 使用多态建立一個狗
26 Animal an = new Dog();
27 an.eat(); // 狗在吃飯
28 System.out.println(an.age); // 100
29 an.lookHome(); // 報錯 無法調用子類特有方法
30 }
31 }
綜上述所:
- 多态的優點:配合繼承與方法重寫提高代碼的複用性與擴充性
- 多态的弊端:多态隻能調用子父類共有的方法,不能調用子類的特有方法
多态本身是子類類型向父類類型向上轉型的過程
多态的轉型分為向上轉型與向下轉型兩種:
向上轉型:當有子類對象指派給一個父類引用時,便是向上轉型,多态本身就是向上轉型的過程
使用格式:
如:Animal p = new Cat();
向下轉型:一個已經向上轉型的子類對象可以使用強制類型轉換的格式,将父類引用轉為子類引用,
這個過程是向下轉型。如果是直接建立父類對象就無法向下轉型的!
子類類型 變量名 = (子類類型) 父類類型的變量;
如:Cat c = (Cat) a; // 變量a實際上指向Cat對象
向下轉型可以解決多态的弊端(不能調用子類的特有方法),執行個體如下:
1 class Animal {
2 int age = 100;
3 public void eat(){
4 System.out.println("動物在吃飯");
5 }
6 }
7
8 class Dog extends Animal{
9 int age = 1000;
10
11 public void eat() {
12 // TODO Auto-generated method stub
13 System.out.println("狗在吃飯");
14 }
15
16 public void lookHome(){
17 System.out.println("狗在看門");
18 }
19
20 }
21
22
23 public class DuoTaiDemo {
24 public static void main(String[] args) {
25 // 使用多态建立一個狗
26 Animal an = new Dog();
27 an.eat(); // 狗在吃飯
28 System.out.println(an.age); // 100
29 // an.lookHome(); // 報錯
30 Dog d = (Dog)an; // 向下轉型
31 d.lookHome();
32 }
33 }
案例描述 - 筆記本電腦案例:
定義USB接口(具備開啟功能、關閉功能),筆記本要使用USB裝置,即筆記本在生産時需要預留
可以插入USB裝置的USB接口,即就是筆記本具備使用USB裝置的功能,但具體是什麼USB裝置,
筆記本并不關心,隻要符合USB規格的裝置都可以。滑鼠和鍵盤要想能在電腦上使用,那麼滑鼠和
鍵盤也必須遵守USB規範,不然滑鼠和鍵盤的生産出來無法使用
進行描述筆記本類,實作筆記本使用USB滑鼠、USB鍵盤
- l USB接口,包含開啟功能、關閉功能
- l 筆記本類,包含運作功能、關機功能、使用USB裝置功能
- l 滑鼠類,要符合USB接口
- l 鍵盤類,要符合USB接口
思路:
USB接口功能抽象成接口 =》開啟USB、關閉USB、使用USB
筆記本類使用USB裝置功能其實就是在調用USB接口中的方法
代碼如下:
1 // USB接口
2 public interface USBInterface {
3 public abstract void open();
4 public abstract void use();
5 public abstract void close();
6 }
1 // USB實作類及Computer類代碼
2 class Computer {
3 public void start() {
4 System.out.println("電腦開機");
5 }
6
7 public void end() {
8 System.out.println("電腦關機");
9 }
10
11 // 使用USB裝置
12 public void useUSB(USBInterface usb){
13 usb.open();
14 usb.use();
15 usb.close();
16 }
17
18 }
19
20 class KeyBoard implements USBInterface{
21
22 public void open() {
23 System.out.println("鍵盤打開");
24 }
25
26 public void use() {
27 System.out.println("使用鍵盤");
28 }
29
30 public void close() {
31 System.out.println("鍵盤關閉");
32 }
33
34 }
35
36 class Mouse implements USBInterface{
37 public void open() {
38 System.out.println("滑鼠打開");
39 }
40
41 public void use() {
42 System.out.println("使用滑鼠");
43 }
44
45 public void close() {
46 System.out.println("滑鼠關閉");
47 }
48 }
49
50 public class ComputerDemo {
51 public static void main(String[] args) {
52 Computer t = new Computer();
53 Mouse ms = new Mouse();
54 KeyBoard kb = new KeyBoard();
55 t.start();
56 t.useUSB(ms);
57 t.useUSB(kb);
58 t.end();
59 }
60 }
too young too simple sometimes native!