2020-05-17--Java--day10【多態(tài)】

多態(tài)概述

多態(tài)的格式和使用

代碼當中體現(xiàn)多態(tài)性,其實就是一句話:父類引用指向子類對象。

格式:

  • 父類名稱 對象名 = new 子類名稱();
  • 接口名稱 對象名 = new 實現(xiàn)類名稱();

FU類:

public class Fu {

    public void method() {
        System.out.println("父類方法");
    }

    public void methodFu() {
        System.out.println("父類特有方法");
    }
}

ZI類:

public class Zi extends Fu {

    @Override
    public void method() {
        System.out.println("子類方法");
    }
}

main方法:

public class Demo01Multi {

    public static void main(String[] args) {
        // 使用多態(tài)的寫法
        // 左側(cè)父類的引用浅妆,指向了右側(cè)子類的對象
        Fu obj = new Zi();

        obj.method();
        obj.methodFu();
    }
}

運行:


多態(tài)中成員變量和成員方法的使用特點

訪問成員變量的兩種方式:

    1. 直接通過對象名稱訪問成員變量:看等號左邊是誰皿渗,優(yōu)先用誰樊拓,沒有則向上找洁闰。
    1. 間接通過成員方法訪問成員變量:看該方法屬于誰,優(yōu)先用誰赘阀,沒有則向上找益缠。

在多態(tài)的代碼當中,成員方法的訪問規(guī)則是:
看new的是誰基公,就優(yōu)先用誰幅慌,沒有則向上找。
口訣:編譯看左邊轰豆,運行看右邊胰伍。
對比一下:
成員變量:編譯看左邊,運行還看左邊秒咨。
成員方法:編譯看左邊喇辽,運行看右邊。
意思是:在調(diào)用成員變量或者成員方法時雨席,要看等號左邊的類中是否有該變量或者該方法菩咨。

FU類:

public class Fu /*extends Object*/ {

    int num = 10;

    public void showNum() {
        System.out.println(num);
    }

    public void method() {
        System.out.println("父類方法");
    }

    public void methodFu() {
        System.out.println("父類特有方法");
    }

}

ZI類:

public class Zi extends Fu {

    int num = 20;

    int age = 16;

    @Override
    public void showNum() {
        System.out.println(num);
    }

    @Override
    public void method() {
        System.out.println("子類方法");
    }

    public void methodZi() {
        System.out.println("子類特有方法");
    }
}

main方法:

public class Demo01MultiField {

    public static void main(String[] args) {
        // 使用多態(tài)的寫法,父類引用指向子類對象
        Fu obj = new Zi();
        System.out.println(obj.num); // 父:10
//        System.out.println(obj.age); // 錯誤寫法陡厘!
        System.out.println("=============");

        // 子類沒有覆蓋重寫抽米,就是父:10
        // 子類如果覆蓋重寫,就是子:20
        obj.showNum();
        
        //成員方法的使用
        obj.method(); // 父子都有糙置,優(yōu)先用子
        obj.methodFu(); // 子類沒有云茸,父類有,向上找到父類

        // 編譯看左邊谤饭,左邊是Fu标捺,F(xiàn)u當中沒有methodZi方法懊纳,所以編譯報錯。
//        obj.methodZi(); // 錯誤寫法亡容!
    }

}

總結(jié):

  • 直接調(diào)用成員變量時嗤疯,等號左邊是誰,就用誰的成員變量闺兢,沒有就向上找茂缚。
  • 調(diào)用成員方法時,new的是誰的對象屋谭,就優(yōu)先用誰的方法脚囊,沒有就想上找,但是當在子類中找到該成員方法時桐磁,父類中必須要有該方法悔耘。
Fu obj = new Zi();
含義:受父類限制的子類對象,優(yōu)先執(zhí)行子類中復寫的父類方法所意,但是不能執(zhí)行父類中沒有的方法淮逊。

使用多態(tài)的好處

對象的上下轉(zhuǎn)型

向上轉(zhuǎn)型:

向上轉(zhuǎn)型就是類似于多態(tài)寫法,加入貓繼承于動物類扶踊,那么將貓看作動物就沒毛病,

創(chuàng)建格式::父類 obj = new 子類();

舉例:

Animal類:

public abstract class Animal {

    public abstract void eat();

}

Cat 類:

public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("貓吃魚");
    }
    // 子類特有方法
    public void catchMouse() {
        System.out.println("貓抓老鼠");
    }

main方法:

public class Demo01Main {

    public static void main(String[] args) {
        // 對象的向上轉(zhuǎn)型郎任,就是:父類引用指向之類對象秧耗。
        Animal animal = new Cat(); // 本來創(chuàng)建的時候是一只貓
        animal.eat(); // 貓吃魚

//        animal.catchMouse(); // 錯誤寫法!

但是這是再調(diào)用子類中特有的方法時舶治,就會報錯分井,因為這時對象已經(jīng)向上轉(zhuǎn)型,不能調(diào)用子類中父類沒有的方法霉猛。

向下轉(zhuǎn)型

對象的向下轉(zhuǎn)型其實是一個還原動作尺锚,類似于強制類型轉(zhuǎn)換。當貓類向上轉(zhuǎn)型到動物類后惜浅,再向下轉(zhuǎn)型為貓時瘫辩,沒問題。但是如果將這個之前是貓的動物類向下轉(zhuǎn)型為狗時坛悉,就不對了伐厌。

創(chuàng)建格式:子類名稱 對象名 = (子類名稱) 原本父類對象名;

含義:將父類對象還原為子類對象。

注意事項:在向下轉(zhuǎn)型之前裸影,必須保證該對象在創(chuàng)建時就是該子類的對象(貓)挣轨,這樣才能再次向下轉(zhuǎn)型為貓。
如果不是一個子類的話轩猩,就會報出ClassCastException的錯誤卷扮。

舉例:

Animal類:

public abstract class Animal {

    public abstract void eat();
}

Cat類:

public class Cat extends Animal {

    @Override
    public void eat() {
        System.out.println("貓吃魚");
    }

    // 子類特有方法
    public void catchMouse() {
        System.out.println("貓抓老鼠");
    }
}

Dog類:

public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃SHIT");
    }

    public void watchHouse() {
        System.out.println("狗看家");
    }
}

main類:

public class Demo01Main {

    public static void main(String[] args) {
        // 對象的向上轉(zhuǎn)型荡澎,就是:父類引用指向之類對象。
        Animal animal = new Cat(); // 本來創(chuàng)建的時候是一只貓
        animal.eat(); // 貓吃魚

//        animal.catchMouse(); // 錯誤寫法晤锹!


        // 向下轉(zhuǎn)型衔瓮,進行“還原”動作
        Cat cat = (Cat) animal;
        cat.catchMouse(); // 貓抓老鼠

        // 下面是錯誤的向下轉(zhuǎn)型
        // 本來new的時候是一只貓,現(xiàn)在非要當做狗
        // 錯誤寫法抖甘!編譯不會報錯热鞍,但是運行會出現(xiàn)異常:
        // java.lang.ClassCastException,類轉(zhuǎn)換異常
        Dog dog = (Dog) animal;
    }

}

分析:

  1. 在向上轉(zhuǎn)型后衔彻,父類對象animal不能調(diào)用子類Cat的特有方法薇宠,那么對他進行向下轉(zhuǎn)型,然后就可以調(diào)用了艰额。
  2. 將父類對象animal轉(zhuǎn)為子類Dog時澄港,編譯不會報錯,但是運行異常java.lang.ClassCastException柄沮,類轉(zhuǎn)換異常
  3. 說明只能向下轉(zhuǎn)型為之前創(chuàng)建對象時的子類回梧。

類型判斷----instanceof關(guān)鍵字

在上一步中,我們是怎么知道該父類對象animal之前的引用是貓還是狗祖搓。

所以要進行類型的判斷狱意,使用instanceof關(guān)鍵字。
instanceof 嚴格來說是Java中的一個雙目運算符拯欧,用來測試一個對象是否為一個類的實例详囤,用法為:
對象名稱 instanceof 類名稱

實例:

/*
如何才能知道一個父類引用的對象,本來是什么子類镐作?
格式:
對象 instanceof 類名稱
這將會得到一個boolean值結(jié)果藏姐,也就是判斷前面的對象能不能當做后面類型的實例。
 */
public class Demo02Instanceof {

    public static void main(String[] args) {
        Animal animal = new Dog(); // 本來是一只狗
        animal.eat(); // 狗吃SHIT

        // 如果希望掉用子類特有方法该贾,需要向下轉(zhuǎn)型
        // 判斷一下父類引用animal本來是不是Dog
        if (animal instanceof Dog) {
            Dog dog = (Dog) animal;
            dog.watchHouse();     //狗看家
        }
        // 判斷一下animal本來是不是Cat
        if (animal instanceof Cat) {
            Cat cat = (Cat) animal;
            cat.catchMouse();
        }
        // 調(diào)用給寵物的方法羔杨,傳進去Dog類對象
        giveMeAPet(animal);
    }

    public static void giveMeAPet(Animal animal) {
        if (animal instanceof Dog) {
            Dog dog = (Dog) animal;
            dog.watchHouse();
        }
        if (animal instanceof Cat) {
            Cat cat = (Cat) animal;
            cat.catchMouse();
        }
    }
}

分析:

  1. 首先創(chuàng)建Dog類對象,向上轉(zhuǎn)型為Animal類杨蛋,在使用時兜材,由于不知道該對象之前是哪個類的對象,所以要進行判斷該對象是什么類型的類對象六荒,使用instanceof關(guān)鍵字护姆,返回bool值,進而進行向下轉(zhuǎn)型掏击,就可以調(diào)用該子類中的特有方法了卵皂。

筆記本接口案例

  • 筆記本電腦(laptop)通常具備使用USB設(shè)備的功能。在生產(chǎn)時砚亭,筆記本都預留了可以插入USB設(shè)備的USB接口灯变,
    但具體是什么USB設(shè)備殴玛,筆記本廠商并不關(guān)心,只要符合USB規(guī)格的設(shè)備都可以添祸。
  • 定義USB接口滚粟,具備最基本的開啟功能和關(guān)閉功能。鼠標和鍵盤要想能在電腦上使用刃泌,那么鼠標和鍵盤也必須遵守USB規(guī)范凡壤,實現(xiàn)USB接口,否則鼠標和鍵盤的生產(chǎn)出來也無法使用耙替。

分析

進行描述筆記本類亚侠,實現(xiàn)筆記本使用USB鼠標、USB鍵盤

  • USB接口俗扇,包含開啟功能硝烂、關(guān)閉功能
  • 筆記本類,包含運行功能铜幽、關(guān)機功能滞谢、使用USB設(shè)備功能
  • 鼠標類,要實現(xiàn)USB接口除抛,并具備點擊的方法
  • 鍵盤類狮杨,要實現(xiàn)USB接口,具備敲擊的方法

圖例:

代碼:
1.定義USB接口:
該接口有兩個抽象類--打開設(shè)備和關(guān)閉設(shè)備

public interface USB {

    public abstract void open(); // 打開設(shè)備

    public abstract void close(); // 關(guān)閉設(shè)備

}

2.定義鼠標類和(鍵盤類)
這兩個類繼承USB接口镶殷,實現(xiàn)接口中的抽象方法禾酱,并有獨有的動作方法--click()和type()

// 鼠標就是一個USB設(shè)備
public class Mouse implements USB {
    @Override
    public void open() {
        System.out.println("打開鼠標");
    }

    @Override
    public void close() {
        System.out.println("關(guān)閉鼠標");
    }

    public void click() {
        System.out.println("鼠標點擊");
    }
}
// 鍵盤就是一個USB設(shè)備
public class Keyboard implements USB {
    @Override
    public void open() {
        System.out.println("打開鍵盤");
    }

    @Override
    public void close() {
        System.out.println("關(guān)閉鍵盤");
    }

    public void type() {
        System.out.println("鍵盤輸入");
    }
}

3.定義電腦類
電腦類實現(xiàn)獨有方法--開機和關(guān)機。
定義使用USB設(shè)備的方法绘趋,該方法的參數(shù)類型為USB類型,在方法中
首先打開設(shè)備(執(zhí)行公有方法打開設(shè)備)颗管,判斷設(shè)備類型陷遮,執(zhí)行設(shè)備特有方法,關(guān)閉設(shè)備(執(zhí)行共有方法)

public class Computer {

    public void powerOn() {
        System.out.println("筆記本電腦開機");
    }

    public void powerOff()  {
        System.out.println("筆記本電腦關(guān)機");
    }

    // 使用USB設(shè)備的方法垦江,使用接口作為方法的參數(shù)
    public void useDevice(USB usb) {
        usb.open(); // 打開設(shè)備
        if (usb instanceof Mouse) { // 一定要先判斷
            Mouse mouse = (Mouse) usb; // 向下轉(zhuǎn)型
            mouse.click();
        } else if (usb instanceof Keyboard) { // 先判斷
            Keyboard keyboard = (Keyboard) usb; // 向下轉(zhuǎn)型
            keyboard.type();
        }
        usb.close(); // 關(guān)閉設(shè)備
    }

}

Main:

public class DemoMain {

    public static void main(String[] args) {
        // 首先創(chuàng)建一個筆記本電腦
        Computer computer = new Computer();
        computer.powerOn();

        // 準備一個鼠標帽馋,供電腦使用
//        Mouse mouse = new Mouse();
        // 首先進行向上轉(zhuǎn)型
        USB usbMouse = new Mouse(); // 多態(tài)寫法
        // 參數(shù)是USB類型,我正好傳遞進去的就是USB鼠標
        computer.useDevice(usbMouse);

        // 創(chuàng)建一個USB鍵盤
        Keyboard keyboard = new Keyboard(); // 沒有使用多態(tài)寫法
        // 方法參數(shù)是USB類型比吭,傳遞進去的是實現(xiàn)類對象
        computer.useDevice(keyboard); // 正確寫法绽族!也發(fā)生了向上轉(zhuǎn)型
        // 使用子類對象,匿名對象衩藤,也可以
//        computer.useDevice(new Keyboard()); // 也是正確寫法

        computer.powerOff();
        System.out.println("==================");

        method(10.0); // 正確寫法吧慢,double --> double
        method(20); // 正確寫法,int --> double
        int a = 30;
        method(a); // 正確寫法赏表,int --> double
    }

    public static void method(double num) {
        System.out.println(num);
    }

}

Main函數(shù)分析:

  1. 首先創(chuàng)建一個筆記本類检诗,執(zhí)行筆記本的開機方法(powerOn)匈仗。
  2. 接入鼠標時,使用多態(tài)寫法將鼠標類向上轉(zhuǎn)型為USB接口類創(chuàng)建對象逢慌,將該對象傳入電腦類的USB使用方法中(useDevice)悠轩,這是常規(guī)寫法,符合要求攻泼,進而在該方法中執(zhí)行鼠標類中實現(xiàn)USB接口類的打開設(shè)備和關(guān)閉設(shè)備的兩個方法火架,并判斷類型為鼠標類,執(zhí)行獨有方法--點擊(click)忙菠。
  3. 接入鍵盤何鸡,不在顯式的將鍵盤類向上轉(zhuǎn)為USB接口類,采用正常寫法創(chuàng)建鍵盤類對象只搁,進而調(diào)用電腦類的使用USB的方法音比,將鍵盤對象傳進去,執(zhí)行該方法氢惋。(與鼠標執(zhí)行一致)
  • 第三部也是正確的洞翩,原因就是發(fā)生了類似于自動類型轉(zhuǎn)換的情況,例如:定義一個接受double類型參數(shù)的方法焰望,當傳入int類型時骚亿,也是可以的,發(fā)生自動類型轉(zhuǎn)換熊赖,將int轉(zhuǎn)為double類型来屠。

4.關(guān)閉電腦--執(zhí)行powerOff方法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末震鹉,一起剝皮案震驚了整個濱河市俱笛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌传趾,老刑警劉巖迎膜,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異浆兰,居然都是意外死亡磕仅,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門簸呈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來榕订,“玉大人,你說我怎么就攤上這事蜕便〗俸悖” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵玩裙,是天一觀的道長兼贸。 經(jīng)常有香客問我段直,道長,這世上最難降的妖魔是什么溶诞? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任鸯檬,我火速辦了婚禮,結(jié)果婚禮上螺垢,老公的妹妹穿的比我還像新娘喧务。我一直安慰自己,他們只是感情好枉圃,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布功茴。 她就那樣靜靜地躺著,像睡著了一般孽亲。 火紅的嫁衣襯著肌膚如雪坎穿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天返劲,我揣著相機與錄音玲昧,去河邊找鬼。 笑死篮绿,一個胖子當著我的面吹牛孵延,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播亲配,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼尘应,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了吼虎?” 一聲冷哼從身側(cè)響起犬钢,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎思灰,沒想到半個月后娜饵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡官辈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了遍坟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拳亿。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖愿伴,靈堂內(nèi)的尸體忽然破棺而出肺魁,到底是詐尸還是另有隱情,我是刑警寧澤隔节,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布鹅经,位于F島的核電站寂呛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瘾晃。R本人自食惡果不足惜贷痪,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蹦误。 院中可真熱鬧劫拢,春花似錦、人聲如沸强胰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽偶洋。三九已至熟吏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間玄窝,已是汗流浹背牵寺。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留哆料,地道東北人缸剪。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像东亦,于是被迫代替她去往敵國和親杏节。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351