JAVA面向對象之多態


面向對象之多態

例子

class Person{}

class Boy extends Person{}

class Girl extends Person{}

一、多態的定義

生活上:

  • 通俗的講,就是同一個東西表現出多種狀態
  • 比如我開頭的例子,男孩,女孩都是人類。是人類的不同狀態

程序上:

  • 父類引用指向子類的實例
  • 同一個引用類型,使用不同的實例而執行不同操作
  • 當我們使用父類的引用,指向子類的實例的時候,實際上就是一個向上轉型的過程

我們一般在創建對象的時候

Boy boy = new Boy();

Girl girl = new Girl();

而多態的創建

//父類的引用指向子類的對象
//前面是父類聲明 = 新建一個子類的對象
Person p = new Boy();

我們可以直接輸出這個父類看一下

Person p = new Boy();
System.out.println(p);

運行結果:

Boy@2503dbd3

發現我們運行的時候識別到了它是Boy類

也就是說我們在編譯前它被識別為父類,而編譯后也就是運行的時候就被識別為子類了

這就是多態

編譯的時候創建父類引用指向子類的對象

而特性是運行的時候就已經是子類的對象了

二、為什么使用多態

我們來看這樣一個場景

我們人都是要吃飯的,都有吃飯這個行為

class Person {
    public void eat(){
        System.out.println("是人就得吃飯");
    }
}

雖然人都得吃飯,但是針對到男孩,女孩在吃飯上是有一定的差異的。

就需要重寫一下父類的方法了

//男孩 
class Boy extends Person{
    public void eat(){
        super.eat();
        System.out.println("男孩要力氣,得吃肉");
    }
}
//女孩
class Girl extends Person{
     public void eat() {
         super.eat();
         System.out.println("女孩要苗條,得少吃");
     }
 }

我們假設一個食堂類,食堂里是男孩,女孩吃飯的地方

class Canteen{
    public void meal(Boy boy){
        System.out.println("到食堂干飯");
        boy.eat();
    }

    public void meal(Girl girl){
        System.out.println("到食堂干飯");
        girl.eat();
    }
}

那么我們想要男孩,女孩都能進去吃飯,我們就需要進行重載,才能識別所有的參數

測試代碼:

Canteen c = new Canteen();
Boy boy = new Boy();
c.meal(boy);

但是這樣就會有一個問題

我們這里是只有男孩和女孩這兩個類,重載了一次,代碼開始有些重復了。

我們之前說過代碼重復,我們就需要找到合適的方法解決重復的代碼

為什么使用多態

  • 為了解決重復代碼
  • 為了完善項目結構

三、如何實現多態

我們一開始說過,父類引用指向子類的對象是多態,該如何運用呢

Person p = new boy();
p.eat();

我們發現調用的是子類重寫父類的方法

實際上多態的使用就這么簡單

  • 系統會自動進行類型轉換

  • 通過父類引用變量調用的方法是子類覆蓋或繼承的子類方法,不是父類的方法

  • 通過父類引用變量無法調用子類特有的方法

1、通過方法參數

將我們參數從子類改為父類

代碼如下

class Canteen{
    public void meal(Person person){
        System.out.println("到食堂干飯");
        boy.eat();
    }
}

我們測試傳參,測試代碼不需要更改

Canteen c = new Canteen();
Boy boy = new Boy();
c.meal(boy);
//測試的參數不需要改變

也是能夠實現的,但是不需要重載

這個能夠實現是因為形參Person person就是創建了一個父類的引用

當我們傳參的時候,就是使父類指向了子類的對象

2、通過方法的返回值

這個就更簡單了

我們先寫一個方法

代碼如下

public Person getPerson(String choose){
    if(choose.equals("boy")){
        return new Boy();
    }else if(choose.equals("girl")){
        return new Girl();
    }else{
        System.out.println("輸入有誤");
        return null;
    }
}

當我們調用該方法的時候,通過參數選擇,返回男孩或者女孩。

返回的都是一個Person類型的,但是卻是一個父類的引用指向子類的對象

四、注意點

1、轉型問題

剛才說過,父類引用指向子類的對象,是向上轉型。

//左邊是父類  右邊是子類
//和以前學習基礎類型時候的默認強轉很像
//int a = short
Person p = new Boy();

有向上轉型就有想下轉向

//向下轉型的注意點是:能被轉為子類的父類,一定是父類引用指向子類的對象
//能轉成功,也必須是父類指向的就是這個子類才行
//同樣和基礎類型的強轉很像
//short a = (short)int
Boy b =(Boy)p;

2、確保轉型成功--instanceof關鍵字

我們是已知當前這個對象是父類指向的某個子類

所以直接能夠將父類向下轉型為子類

但是我們可以看下面代碼

Person p = new Boy();
Girl g = (girl)p;

運行之后就告訴我們,是沒辦法將Boy類轉為Girl類

我們明顯的發現一定需要轉為對應的子類才能成功。

所以我們需要一些判斷手段

boolean a = p instanceof Boy;
//我們發現返回的是true

由此我們可以看出來

[對象名] instanceof [類];
//判斷對象是否是該類的
//是返回true 否返回false

這樣,我們就可以直接先判斷再強轉了

if(p instanceof Boy){
    Boy b =(Boy)p;
}

可保萬無一失

3、為什么需要強轉

我們本來今天就是為了使用父類引用子類的對象去操作,為什么還需要進行強轉回去呢

我們發現,使用多態沒有辦法調用子類獨有的方法,當我們需要調用子類獨有的方法的時候,我們進行強轉然后再調用

五、面向對象小結

面向對象的三大特性:封裝、繼承、多態

  • 封裝是隱藏對象的屬性和實現細節

    • 將類的成員屬性聲明為私有的,同時提供公有的方法實現對該成員屬性的存取操作
  • 繼承是軟件可重用性的一種表現

    • 新類可以在不增加自身代碼的情況下,通過從現有的類中繼承其屬性和方法充實自身內容
  • 多態是具有表現多種形態的能力的特征

    • 在程序設計的術語中,意味着一個特定類型的變量可以引用不同類型的對象,自動地調用引用的對象的方法
      • 即根據作用到的不同對象類型,響應不同的操作

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM