20.面向?qū)ο筮M(jìn)階:多態(tài),強(qiáng)制類型轉(zhuǎn)換,instanceof關(guān)鍵字,接口實(shí)現(xiàn)類多態(tài)綜合案例

面向?qū)ο笕蠡咎卣髦憾鄳B(tài)

多態(tài)的概述,多態(tài)的形式

  • 多態(tài)的定義:

    • 同類型的對(duì)象,執(zhí)行同一個(gè)行為,會(huì)表現(xiàn)出不同的行為特征
  • 多態(tài)的常見形式:

    • 父類類型 對(duì)象名稱 = new 子類構(gòu)造器;
      接口 對(duì)象名稱 = new 實(shí)現(xiàn)類構(gòu)造器;
      
    • 測(cè)試案例:

      package com.java.PolymorphicTest;
      
      public abstract class Animal {
          // 為方便測(cè)試統(tǒng)一采用public
          public String name = "父類動(dòng)物";
      
          public abstract void run();
      }
      
      package com.java.PolymorphicTest;
      
      public class Dog extends Animal {
      
          public String name = "子類狗";
      
          @Override
          public void run() {
              System.out.println("小狗跑的很快!");
          }
      }
      
      package com.java.PolymorphicTest;
      
      public class Tortoise extends Animal {
          public String name = "子類烏龜";
      
          @Override
          public void run() {
              System.out.println("烏龜跑的很慢!");
          }
      }
      
      package com.java.PolymorphicTest;
      
      public class Test {
          public static void main(String[] args) {
              Animal d = new Dog();
              d.run();
              System.out.println(d.name);
              System.out.println("========================");
              Animal t = new Tortoise();
              t.run();
              System.out.println(d.name);
      
              System.out.println("============多態(tài)第二個(gè)優(yōu)勢(shì),父類作為方法形參,可以將所有子類對(duì)象傳進(jìn)來============");
              go(d);
              go(t);
          }
      
          /**
           * 多態(tài)第二個(gè)優(yōu)勢(shì)
           */
          public static void go(Animal a) {
              a.run();
          }
      }
      /*
      小狗跑的很快!
      父類動(dòng)物
      ========================
      烏龜跑的很慢!
      父類動(dòng)物
      ============多態(tài)第二個(gè)優(yōu)勢(shì),父類作為方法形參,可以將所有子類對(duì)象傳進(jìn)來============
      小狗跑的很快!
      烏龜跑的很慢!
      
       */
      
  • 多態(tài)中成員訪問特點(diǎn):

    • 成員方法調(diào)用:編譯看左邊,運(yùn)行看右邊

      編譯的時(shí)候會(huì)看向左邊父類的成員方法,具體運(yùn)行時(shí)會(huì)運(yùn)行右邊子類對(duì)象的方法

    • 成員變量調(diào)用:編譯看左邊,運(yùn)行也看左邊(多態(tài)是側(cè)重行為的多態(tài))

      成員變量的調(diào)用,不管編譯還是運(yùn)行,都看向父類的一方(如上述測(cè)試代碼name的值均為父類動(dòng)物)

  • 多態(tài)的前提:

    • 有繼承/實(shí)現(xiàn)關(guān)系
    • 有父類引用指向子類對(duì)象
    • 有方法重寫

多態(tài)的好處

  • 在多態(tài)形勢(shì)下,右邊對(duì)象可以實(shí)現(xiàn)解耦合,便于擴(kuò)展和維護(hù)

    組件化的解耦合即組件之間的依賴沒有那么強(qiáng)

    Animal a = new Dog();
    a.run();
    
    //當(dāng)Dog類換成其他類,即對(duì)象發(fā)生了變化,后續(xù)業(yè)務(wù)行為隨對(duì)象而變,后續(xù)的代碼邏輯無需修改
    
    Animal a = new Cat();
    a.run();
    
  • 定義方法的時(shí)候,使用父類型作為參數(shù),該方法就可以接收這父類的一切子類對(duì)象,體現(xiàn)出多態(tài)的擴(kuò)展性與便利

    參照上方測(cè)試案例代碼


  • 多態(tài)下會(huì)產(chǎn)生的一個(gè)問題:
    • 多態(tài)下不能使用 子類的獨(dú)有功能

多態(tài)下引用數(shù)據(jù)類型的類型轉(zhuǎn)換

為了解決多態(tài)下不能調(diào)用子類獨(dú)有功能的弊端提出引用數(shù)據(jù)類型的類型轉(zhuǎn)換

  • 自動(dòng)類型轉(zhuǎn)換(從子到父):子類對(duì)象可以直接賦值給父類類型的變量指向

  • 強(qiáng)制類型轉(zhuǎn)換(從父到子):

    • 此時(shí)必須進(jìn)行強(qiáng)制類型轉(zhuǎn)換:子類 對(duì)象變量 = (子類)父類類型的變量

    • 作用:可以解決多態(tài)下的劣勢(shì),可以實(shí)現(xiàn)調(diào)用子類獨(dú)有的功能

    • 注意:如果轉(zhuǎn)型后的類型和對(duì)象真實(shí)類型不是同一種類型,那么在轉(zhuǎn)換的時(shí)候就會(huì)出現(xiàn)ClassCastException

      強(qiáng)制類型轉(zhuǎn)換,編譯階段不報(bào)錯(cuò)的(注意:有繼承或者實(shí)現(xiàn)關(guān)系編譯階段可以強(qiáng)制轉(zhuǎn)換,但是運(yùn)行時(shí)可能出錯(cuò))

      例如,Dog d = (Dog) a2;編譯器認(rèn)為程序員希望將Animal類的對(duì)象a2轉(zhuǎn)換成Dog類型并指向Dog類型的d,因此編譯階段放行,但是在運(yùn)行時(shí)發(fā)現(xiàn),d不是Dog的對(duì)象,而是烏龜?shù)膶?duì)象,指向有問題,張冠李戴,于是報(bào)錯(cuò)

    • Java建議強(qiáng)轉(zhuǎn)前使用instanceof關(guān)鍵字判斷當(dāng)前對(duì)象的真實(shí)類型,然后再強(qiáng)制轉(zhuǎn)換

      變量名 instanceof 真實(shí)類型
      // 判斷關(guān)鍵字左邊的變量指向的對(duì)象的真實(shí)類型,是否是右邊的類型或者是其子類型,是則返回true,反之返回false
      
  • 測(cè)試代碼:

    package com.java.PolymorphicDisadvantages;
    
    public class Animal {
        public void run(){
            System.out.println("動(dòng)物可以跑!");
        }
    }
    
    package com.java.PolymorphicDisadvantages;
    
    public class Dog extends Animal {
        @Override
        public void run() {
            System.out.println("??跑的快");
        }
    
        /**
         * 獨(dú)有功能
         */
        public void lookDoor() {
            System.out.println("??看門");
        }
    
    }
    
    package com.java.PolymorphicDisadvantages;
    
    
    public class Tortoise extends Animal {
        @Override
        public void run() {
            System.out.println("??跑的很慢!");
        }
    
        /**
         * 獨(dú)有功能
         */
        public void layEggs() {
            System.out.println("??可以下蛋");
        }
    }
    
    
    package com.java.PolymorphicDisadvantages;
    
    public class Test {
        public static void main(String[] args) {
            // 自動(dòng)類型轉(zhuǎn)換
            Animal a = new Dog();
            a.run();
    
            // 強(qiáng)制類型轉(zhuǎn)換
            Animal a2 = new Tortoise();
            Tortoise t = (Tortoise) a2;
            Dog d = (Dog) a;
            d.lookDoor();
            t.layEggs();
    
            System.out.println(d instanceof Dog);   // true
            System.out.println(t instanceof Tortoise);  // true
            System.out.println(d instanceof Tortoise);   // 在編譯階段直接報(bào)紅,由此可知類型不匹配
    
        }
    }
    

多態(tài)的綜合案例

  • 需求:

    • 使用面向?qū)ο缶幊棠M:設(shè)計(jì)一個(gè)電腦對(duì)象,可以安裝2個(gè)USB設(shè)備
    • 鼠標(biāo):被安裝時(shí)可以完成接入,調(diào)用點(diǎn)擊功能,拔出功能
    • 鍵盤:被安裝時(shí)可以完成接入,調(diào)用打字功能,拔出功能
  • 分析:

    1. 定義一個(gè)USB接口(申明USB設(shè)備的規(guī)范是:可以接入和拔出)
    2. 提供兩個(gè)USB實(shí)現(xiàn)類代表鼠標(biāo)和鍵盤,讓其實(shí)現(xiàn)USB接口,并分別定義獨(dú)有功能
    3. 創(chuàng)建電腦對(duì)象,創(chuàng)建2個(gè)USB實(shí)現(xiàn)類對(duì)象,分別安裝到電腦中并觸發(fā)功能的執(zhí)行
  • 案例代碼:

    package com.java.Polymorphic_Case;
    
    /**
     * usb接口規(guī)范
     */
    public interface USB {
        void connect();
    
        void unconnect();
    }
    
    
    package com.java.Polymorphic_Case;
    
    /**
     * 鼠標(biāo)實(shí)現(xiàn)類
     */
    public class Mouse implements USB {
        private String goodsName;
    
        public Mouse() {
        }
    
        public Mouse(String goodsName) {
            this.goodsName = goodsName;
        }
    
        public String getGoodsName() {
            return goodsName;
        }
    
        public void setGoodsName(String name) {
            this.goodsName = name;
        }
    
        @Override
        public void connect() {
            System.out.println(getGoodsName() + "鼠標(biāo)成功接入");
        }
    
        @Override
        public void unconnect() {
            System.out.println(getGoodsName() + "鼠標(biāo)成功斷開");
        }
    
        /**
         * 鼠標(biāo)獨(dú)有功能:點(diǎn)擊
         */
        public void onClick() {
            System.out.println("使用" + getGoodsName() + "鼠標(biāo)點(diǎn)擊了IDEA中的運(yùn)行按鈕");
        }
    }
    
    
    package com.java.Polymorphic_Case;
    
    import java.util.Scanner;
    
    /**
     * 鍵盤實(shí)現(xiàn)類
     */
    public class KeyBoard implements USB {
        private String goodsName;
    
        public KeyBoard() {
        }
    
        public KeyBoard(String goodsName) {
            this.goodsName = goodsName;
        }
    
        public String getGoodsName() {
            return goodsName;
        }
    
        public void setGoodsName(String goodsName) {
            this.goodsName = goodsName;
        }
    
        @Override
        public void connect() {
            System.out.println(getGoodsName() + "鍵盤成功接入");
        }
    
        @Override
        public void unconnect() {
            System.out.println(getGoodsName() + "鍵盤成功斷開");
        }
    
        /**
         * 鍵盤獨(dú)有功能:打字
         */
        public void keyDone() {
            Scanner scanner = new Scanner(System.in);
            System.out.println("請(qǐng)敲擊鍵盤");
            String str = scanner.next();
            System.out.println("使用" + getGoodsName() + "鍵盤敲擊出一串內(nèi)容:" + str);
        }
    }
    
    
    package com.java.Polymorphic_Case;
    
    public class Computer {
        private String goodsName;
    
    
        public Computer() {
        }
    
        public Computer(String goodsName) {
            this.goodsName = goodsName;
        }
    
        public String getGoodsName() {
            return goodsName;
        }
    
        public void setGoodsName(String goodsName) {
            this.goodsName = goodsName;
        }
    
        /**
         * 提供安裝USB設(shè)備的入口
         */
        public void installUSB(USB usb) { //多態(tài)用法
            usb.connect();
    
            // 獨(dú)有功能調(diào)用
            if (usb instanceof KeyBoard) {
                KeyBoard k = (KeyBoard) usb;
                k.keyDone();
            } else if (usb instanceof Mouse) {
                Mouse m = (Mouse) usb;
                m.onClick();
            }
    
            usb.unconnect();
        }
    
        public void start() {
            System.out.println(getGoodsName() + "電腦開機(jī)了");
        }
    }
    
    
    package com.java.Polymorphic_Case;
    
    public class Test {
        public static void main(String[] args) {
            Computer c = new Computer();
            c.setGoodsName("Thinkpad");
            c.start();
    
            USB u = new KeyBoard("HHKB");
            c.installUSB(u);
    
            USB v = new Mouse("Razer");
            c.installUSB(v);
        }
    }
    
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容