多態

1、什麼是多態函數

「多態」是JAVA的一種重要特性,能夠理解爲事物存在的多種形態。優化

不過,這只是字面上來理解,等於廢話。那麼究竟何爲多種形態呢,接下來,舉一個現實生活中的例子。spa

好比,動物裏有貓和狗。貓擺在面前,你可說它是貓,也能夠說它是動物。code

說它是貓時,用JAVA語句表示即   貓 x=new 貓;對象

說它是動物時,用JAVA語句表示即  動物 x=new 貓;blog

這樣,實體x即具有貓的類型,也具有動物類型。但必須一個前提,即「貓」必須是「動物」中的一種,若是「狗 x=new 貓」就不對了。繼承

經過以上的例子,咱們能夠看出,實體除了具有本類類型,還能夠具有其它類型。這種是「多態」。編譯

 

先看如下代碼,這是使用非多態方式編寫class

代碼以下:變量

package com.duotai;

public class DuoTaiDemo {

    public static void main(String[] args) {

        myFun(new Cat());
        myFun(new Dog());
        myFun(new Pig());
    }

    // 動物「吃」的功能提取出來封裝成函數
    public static void myFun(Cat c) {
        c.eat();
    }

    public static void myFun(Dog d) {
        d.eat();
    }

    public static void myFun(Pig p) {
        p.eat();
    }

}

// 如下定義抽象類,定義了動物有「吃」的功能
abstract class Animal {
    abstract void eat(); // 動物吃什麼不知道,定義成抽象。定義體系中的基本功能。只要繼承了這個類,必有此功能。
}

// 以定義具體類,複寫動物的吃的功能,並有本身獨特的功能
class Cat extends Animal {
    public void eat() { // 複寫Animal類的eat方法
        System.out.println("貓吃魚");
    }

    public void catchMouse() { // 本身特有的方法
        System.out.println("貓抓老鼠");

    }
}

class Dog extends Animal {
    public void eat() { // 複寫Animal類的eat方法
        System.out.println("狗吃骨頭");
    }

    public void kanJia() { // 本身特有的方法
        System.out.println("看家");
    }
}

class Pig extends Animal {
    public void eat() { // 複寫Animal類的eat方法
        System.out.println("豬吃飼料");
    }

    public void gongDi() { // 本身特有的方法
        System.out.println("拱地");
    }
}

 

以上代碼,定義了一個「動物」類,其有一個「吃」的功能,可是因爲每種動物吃的方式都不同,因此定義成抽象類。之後讓具體的動物去複寫。

而後,定義了三個繼承類,「貓」「狗」「豬」,複寫了動物的「吃」的功能。

主函數調用時,要創建子類對的引用對象,再調用吃的方式。

這樣編寫時,會有一個弊端,那就是繼承的子類若是增長時,則要修改主函數中的「吃」的代碼。子類越多,這端代碼就越長,擴展性比較弱。

如何優化呢?

子類「貓」,繼承了「動物」類,是動物中的一種,那就能夠用「動物」的引用來指向子類實例,即Aniaml c=new cat,c.eat(),運行結果是子類的,由於父類中有,子類中也有,就運行子類的eat(),由於子類複寫了。這就是一個事物具有多種形態。

代碼簡化以下:

package com.duotai;

public class DuoTaiDemo {

    public static void main(String[] args) {

        myFun(new Cat());
        myFun(new Dog());
        myFun(new Pig());
    }

    // 動物「吃」的功能提取出來封裝成函數
    public static void myFun(Animal a){        //只要定義Animal便可。至關於Animal a=new Cat();
        a.eat();
    }

}

// 如下定義抽象類,定義了動物有「吃」的功能
abstract class Animal {
    abstract void eat(); // 動物吃什麼不知道,定義成抽象。定義體系中的基本功能。只要繼承了這個類,必有此功能。
}

// 以定義具體類,複寫動物的吃的功能,並有本身獨特的功能
class Cat extends Animal {
    public void eat() { // 複寫Animal類的eat方法
        System.out.println("貓吃魚");
    }

    public void catchMouse() { // 本身特有的方法
        System.out.println("貓抓老鼠");

    }
}

class Dog extends Animal {
    public void eat() { // 複寫Animal類的eat方法
        System.out.println("狗吃骨頭");
    }

    public void kanJia() { // 本身特有的方法
        System.out.println("看家");
    }
}

class Pig extends Animal {
    public void eat() { // 複寫Animal類的eat方法
        System.out.println("豬吃飼料");
    }

    public void gongDi() { // 本身特有的方法
        System.out.println("拱地");
    }
}

 

2、多態的代碼提現形式

  父類的引用引向本身的子類對象。

  父類的引用也能夠接收本身的子類對象。如以上代碼中:Animal a=new Cat()

 

3、多態的做用

  提升了程序的擴展性

 

4、多態的前提

  類與類有關係,必須是繼承或是實現。如以上代碼中,Cat、Dog、Pig類都繼承了Animal類

  一般還有一個前提,就是「複寫」。如以上代碼中,子父類中都有eat()方法,子類複寫父類。

 

5、多態的弊端

  提升了擴展性,可是隻能是父類的引用訪問父類中的成員

 

6、多類中數據的轉型

  在基本數據類型中,存在着數據類型提高現象,如double=2.3+1,會將1由int提高爲double

  在多類中,引用數據也存在數據提高。如以上Animal a=new Cat()中,Animal是父類型,Cat是子類型,將Cat提高爲Animal,稱爲向上轉型。

  若是想要調用調用貓的特有方法(抓老鼠)時,能夠強制將父類的引用轉成子類對象。

  咱們能轉換的是父類引用指向本身的子類對象,該引用能夠被提高,也可被強制向下轉換

  以下:

Animal c=new Cat();//
Cat c1=(Cat)c;        //向下轉型
c1.catchMouse();    //輸出貓的特有方法

 

 

 

在多態中,成員函數的特色:

一、編輯時期,參閱引用型變量所屬的類中是否有調用方法。若是有編譯經過,不然編譯失敗。

以下:Fu f = new Zi(),f所屬的Fu中只有method1和method2,因此輸出method3會編輯失敗。

二、在運行時間,參閱對象所屬的類中是否有調用方法。

以下:

Fu f = new Zi();
f.method1();
f.method2();

調用的是Zi類的方法,

簡單總結,成員函數在多態調用時,編輯看左邊,運行看右邊

以下:

Fu類有method1和method2兩個方法

Zi類中有method1和method3兩個方法

Zi類中method1複寫了Fu類中的method1,Zi類有三個方法

 

 

package com.duotai2;

public class DuoTaiDemo {

    public static void main(String[] args) {
        Fu f = new Zi();
        f.method1();
        f.method2();
        // f.method3();   //編譯失敗     

    }

}

class Fu {
    void method1() {        //
        System.out.println("fu_method_1");
    }

    void method2() {        //
        System.out.println("fu_method_2");
    }
}

class Zi extends Fu {
    void method1() {        //複寫
        System.out.println("zi_method_1");
    }

    void method3() {        //
        System.out.println("zi_method_3");
    }

}

輸出:

zi_method_1
fu_method_2

 

 

在多態中,成員變量的特色:

不管編輯和運行,只參考左邊。以下

package com.duotai2;

public class DuoTaiDemo {

    public static void main(String[] args) {
        Fu f = new Zi();
        System.out.println(f.num);
        Zi z=new Zi();
        System.out.println(z.num);
    }
}

class Fu {
    int num=5;
}

class Zi extends Fu {
    int num=8;
}

輸出:

5

8

 

在多態中,靜態成員函數的特色:

不管編輯和運行,只參考左邊。由於靜態方法不須要建立對象,只要類名調用便可。

以下

public class DuoTaiDemo {

    public static void main(String[] args) {
        Fu f = new Zi();
        f.method4();
        
        Zi z=new Zi();
        z.method4();
    }
}

class Fu {
    static void method4() {        //
        System.out.println("fu_method_4");
    }
}

class Zi extends Fu {
  static void method4() {        //
        System.out.println("zi_method_4");
    }

}

輸出:

fu_method_4zi_method_4

相關文章
相關標籤/搜索