JAVA之Polymorphic(多態)

1.多態的幾個必要條件

1.有繼承關係
2.有方法的重寫
3.父類引用指向子類對象

2.多態中類成員的變現情況

父類:

class Father{
    public int num = 10;

    public String print(){
        return "Father的print()方法!";
    }

    public static String staticprint(){
        return "Father的staticprint()方法";
    }
}

子類:

class Son extends Father{
    public int num = 20;

    public String print(){
        return "Son的print()方法";
    }

    public static String statocprint(){
       return "Son的staticprint()方法";
    }
}

測試類:

public class Main {
    public static void main(String[] args) {
        Father f = new Son();   //父類引用指向子類對象

        System.out.println("f的num值是:" + f.num);
        System.out.println("f的print()調用輸出是:" + f.print());
        System.out.println("f的staticprint()調用輸出是:" + f.staticprint());
    }
}

測試類輸出結果:

f的num值是:10
f的print()調用輸出是:Son的print()方法
f的staticprint()調用輸出是:Father的staticprint()方法

這裏面涉及到子類父類中的成員變量,成員方法,與靜態方法的關係,一一進行解釋。
成員變量:
在這裏插入圖片描述
可以看到在成員變量中,如果一個引用是Father類型的,那麼他在指向堆中對象的時候只能看到Father對象中的變量情況(num = 10),看不到Son對象中的變量情況(num = 20),因此輸出f.num的時候輸出的時輸出的就是Father類中的num值。

成員方法:
在這裏插入圖片描述
在成員方法之中,父類引用指向子類對象之後,要訪問成員方法的時候,編譯的時候對象指向的是父類的方法區,但是運行的時候指向的是子類的方法區域。因此輸出結果的時候輸出的是子類的方法結果,但是因爲編譯的時候會指向父類的方法區,因此如果父類中沒有print()這一方法,則程序在編譯過程中就會報錯!

靜態方法:
靜態方法,即可以用類名進行引用的方法,顯而易見的取決於你的引用類型,該程序中引用類型是Father,因此輸出的結果肯定是父類Father中的靜態方法,與Father.staticprint()的輸出結果是一致的。

總而言之,成員變量,成員方法與靜態方法在多態中編譯時與運行時候的關係就是:
(Father f = new Son())
成員變量:編譯看左邊(Father),運行看左邊(Father);
成員方法:編譯看左邊(Father),運行看右邊(Son);
靜態方法:編譯看左邊(Father),運行看左邊(Father);

3.多態中的向上轉型和向下轉型

Father f = new Son();   //父類引用指向子類對象

父類引用指向子類對象就是向上轉型,即將當前的概念提升爲一個更寬泛的概念。
但是現在的f只能使用Father中有的方法,但是如果我們需要使用Son中特有的方法呢?
就需要向下轉型:

Son s = (Son)f;

即將f專爲一個更加具體的類型。
通過了解向下轉型和向上轉型,就會發現多態的一個弊端,即不能直接使用子類特有的方法,必須得向下轉型。

4.多態的好處和弊端

弊端:不能使用子類特有的屬性和行爲。
好處:提高了代碼的可維護性(繼承保證)和可擴展性(多態保證)。
提高維護性是指因爲繼承的特性,使得我們只需要對父類進行修改就可以影響到繼承於它的所有子類。
可擴展性:

public class Main {
    public static void main(String[] args) {
        method(new Cat());
        method(new Dog());
    }

    public static void method(Cat c){
        c.eat();
    }
}

class Animal{
    public void eat(){
        System.out.println("動物喫飯");
    }
}

class Cat extends Animal{
    public void eat(){
        System.out.println("貓喫魚");
    }

    public void catchmouse(){
        System.out.println("抓老鼠");
    }
}


class Dog extends Animal{
    public void eat(){
        System.out.println("狗喫肉");
    }

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

顯然以上代碼method(new Dog());這個語句是錯誤的,因爲method()方法中傳入的參數是Cat類型的,而這一個句子傳入的參數是Dog類型的,很明顯我們並不能說狗是貓,因此我們如果也想用這種靜態方法的方式來調用Dog中的eat()方法,一種方式就是在重新寫一個method()方法:

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

但是這樣看上去就會顯得代碼十分的多於重複,爲了兩個類型定義兩種方法,那如果有很多種類型的對象,我們就需要定義許多十分相似的方法,這顯然是不允許的,因此我們可以使用多態,因爲Dog和Cat的父類都是Animal,因此我們可以只使用以下一個方法即可:

public static void method(Animal a){
        a.eat();
    }

其實就是這個使用了多態的這兩條語句:

Animal a = new Cat();
Animal a = new Dog();

這顯然是合理的,也是一種更簡潔的做法。這也是多態在實際操作中最經常被運用的情況。

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