多態/動態綁定

假設現在有個需求是:

做一個動物園中各個動物開始吃東西的程序

需求分析:

  1. 定義各種動物對象,動物有名稱等信息以及吃東西的方法;
  2. 定義動物園對象,動物園有名稱等信息;
  3. 實例化出不同的動物對象,並放進動物園,開始吃東西。

代碼部分:

//定義  貓  對象
class Cat{

    private String name;            //貓的名稱
    private String color;           //貓的顏色
    Cat(String name,String color){  //定義帶參構造方法,傳入貓的名稱和特徵
        this.name = name;
        this.color = color;
    };
    public void eat() {               //重寫父類叫的方法,單獨爲貓設置吃食物
        System.out.println("貓吃食物。。。。。");
    }
}
//定義  狗  對象
class Dog{
    private String name;//名稱
    private String type;//種類
    Dog(String name,String type){   //定義帶參構造方法,傳入狗的名稱和特徵
        this.name = name;
        this.type = type;
    };
    public void eat() {               //重寫父類叫的方法,單獨爲狗設置吃食物
        System.out.println("狗吃食物。。。。。");
    }
}
//定義一個  動物園  類
class Zoo{
    private String name;                //動物園名稱
    Zoo(String name){                   //定義帶參構造方法
        this.name = name;
    };
    public void eat(Cat cat)           //讓貓開始吃東西
    {
        cat.eat();                    //調用貓的吃東西的方法
    }
    public void eat(Dog dog)           //讓狗開始吃東西
    {
        dog.eat();                 //調用狗的吃東西的方法
    }
}

啓動程序,開始吃食物:

public static void main(String[] args) {
        Cat cat = new Cat("小花","花色");//new一隻貓
        Dog dog = new Dog("小黑","藏獒");//new一隻狗
        Zoo zoo = new Zoo("大動物園");//new一個動物園
        zoo.eat(cat);//貓在動物開始吃東西
        zoo.eat(dog);//狗在動物園開始吃東西
    }

執行結果:

這樣就完成需求中的  動物園的動物在吃東西。

但是:

如果還有其他動物呢,比如獅子、老虎、孔雀、駱駝.......等等 ,我們就需要在Zoo類中爲每個動物定義不同的吃東西方法。

現在我們使用Java中的繼承來優化一下代碼:

  1. 因爲貓、狗、獅子、老虎等都屬於動物,因此我們可以定義一個動物對象(類型),將動物共有的特性使用動物這個對象(類)來表示:
//定義一個  動物   類
class Animal{
    private String name;                //動物共有的屬性  name  
    Animal(String name){                //聲明帶參構造方法
        this.name = name;
    };
    public void eat()                 //動物共有的  吃食物  的方法
    {
        System.out.println("吃東西。。。。。。");
    }
}

      2.貓、狗等繼承自動物(類):

//定義  貓  對象
class Cat extends Animal{

    private String color;           //貓的顏色
    Cat(String name,String color){  //定義帶參構造方法,傳入貓的名稱和特徵
        super(name);                //將實參傳遞給父類中的name
        this.color = color;
    };
}
//定義  狗  對象
class Dog extends Animal{
    private String type;//種類
    Dog(String name,String type){   //定義帶參構造方法,傳入狗的名稱和特徵
        super(name);                //將實參傳遞給父類中的name
        this.type = type;
    };
}

       3.這時,動物園對象(類)中寫法是這樣的:

//定義一個  動物園  類
class Zoo{
    private String name;                //動物園名稱
    Zoo(String name){                   //定義帶參構造方法
        this.name = name;
    };
    public void eat(Animal animal)           //動物開始吃東西
    {
        animal.eat();                    //調用動物吃東西的方法
    }
}

        4.開始執行:

public static void main(String[] args) {
        Cat cat = new Cat("小花","花色");//new一隻貓
        Dog dog = new Dog("小黑","藏獒");//new一隻狗
        Zoo zoo1 = new Zoo("大動物園");//將貓放進動物園
        zoo1.eat(cat);//貓開始吃東西
        zoo1.eat(dog);//貓開始吃東西
    }

       5.執行結果:

這樣我們就解決了,需要重複爲每個動物定義eat()吃東西這個操作了。

但是:

由於吃eat()這個方法是“動物”對象提供的,因此不能很好的區分哪個動物在吃,我們的需求是要清楚那個動物在吃,象最初代碼執行結果那樣,該怎麼做呢?

解決方法就是,每個動物重寫一下“動物”對象的吃eat()方法,也就是重寫父類方法:

/定義  貓  對象
class Cat extends Animal{

    private String color;           //貓的顏色
    Cat(String name,String color){  //定義帶參構造方法,傳入貓的名稱和特徵
        super(name);
        this.color = color;
    };
    @Override
    public void eat() {               //重寫父類吃的方法,重新爲小貓設置吃食物
        System.out.println("貓吃食物。。。。。");
    }
}
//定義  狗  對象
class Dog extends Animal{
    private String type;//種類
    Dog(String name,String type){   //定義帶參構造方法,傳入狗的名稱和特徵
        super(name);
        this.type = type;
    };
    @Override
    public void eat() {               //重寫父類吃的方法,重新爲小狗設置吃食物
        System.out.println("狗吃食物。。。。。");
    }
}

其他類不變(動物、動物園)

執行結果爲:

好了  大功告成!

這時大家的疑惑可能就是

1.爲什麼在動物園對象中我們eat()參數爲Animal(動物),而傳遞的實參是Cat對象或Dog對象;

2.爲什麼在動物園對象中我們eat()調用的是Animal(動物)的eat(),實際執行出來的確實Cat對象和Dog對象的eat().

解答:

1.因爲我們的Animal對象是其他(Cat對象/Dog對象)的父類,

而java中有這樣一個特性:父類引用可以指向子類對象,也就是說Animal對象中的eat()中的參數Animal對象是一個引用,當我們傳遞其字類對象時,就表示我們將這個父類引用指向了一個子類對象,Java這樣設計的好處就是降低代碼耦合性,提升代碼可擴展性(如:我們後續添加需要其他動物對象,只要其是Animal(動物類)的子類,那麼我們的動物園對象中的代碼是不用改變的)

2.因爲Java有多態,我們的子類(Cat/Dog)繼承自父類並重寫了父類(Animal)中eat(),那麼在調用父類(Animal)中eat()時,在運行期Java會通過判斷我們傳入的是哪個子類對象,再去確定調用對應的eat()(如果子類沒有重寫父類方法,就默認調用父類的eat()),這個就是Java的多態也就是動態綁定。

至此得出:

多態的前提條件:

1.要有繼承;

2.要有重寫;

3.父類引用指向子類對象

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章