Java理解誤區——方法的重載是多態性的一種體現?

理解誤區

學習的第一門語言就是Java了,還記得在初學Java的時候,還是遇到了很多的困難,很多的知識點還不能理解。提到Java的面向對象,相信很多人都會印象深刻吧,但是對於初學者來說,理解起來確實還是有些難度的。

還記得當時很不理解面向對象的多態性,就去問了問學姐,得到的答案是,暫時可以理解,方法的重載是多態性的一種體現,至於更深層次的理解,可以隨着時間以後慢慢理解。

方法的重載是多態性的一種體現嗎? 其實這是一個誤區,讓我很長的一段時間都理解錯了,直到又一次系統複習Java的時候才理解,方法的重載並不是是多態性的一種體現

下面具體談談方法的重載和多態性。

方法的重載

重載:在同一個類中,允許存在一個以上的同名方法,只要它們的參數個數或者參數類型不同即可。

特點

與返回值類型無關,只看參數列表,且參數列表必須不同。 (參數個數或參數類型)。調用時,根據方法參數列表的不同來區別。

"兩同一不同":

  • 同一個類、相同方法名

  • 參數列表不同:參數個數不同,參數類型不同

注:判斷是否爲重載,跟方法的權限修飾符、返回值類型、形參變量名、方法體都沒有關係!

示例

//返回兩個整數的和
int add(int x,int y){return x+y;}

//返回三個整數的和
int add(int x,int y,int z){return x+y+z;}

//返回兩個小數的和
double add(double x,double y){return x+y;}

方法的重載、重寫與多態性(方法的重載是多態性的一種體現?NO)*

從編譯和運行的角度看:
重載,是指允許存在多個同名方法,而這些方法的參數不同。 編譯器根據方法不同的參數表, 對同名方法的名稱做修飾。對於編譯器而言,這些同名方法就成了不同的方法。 它們的調用地址在編譯期就綁定了。 Java的重載是可以包括父類和子類的,即子類可以重載父類的同名不同參數的方法

所以:對於重載而言,在方法調用之前,編譯器就已經確定了所要調用的方法,這稱爲“早綁定”或“靜態綁定” ;

對於多態,只有等到方法調用的那一刻, 解釋運行器纔會確定所要調用的具體方法,這稱爲“晚綁定”或“動態綁定”
引用一句Bruce Eckel的話: “不要犯傻,如果它不是晚綁定, 它就不是多態。

所以說,方法的重載並不是多態性的一種體現

下面來看看多態性

多態性

如何理解多態性?

可以理解爲一個事物的多種形態。

何爲多態性?

對象的多態性:父類的引用指向子類的對象(或子類的對象賦給父類的引用)

  • 可以直接應用在抽象類和接口上

多態性的作用

提高了代碼的通用性,常稱作接口重用

多態性的使用

虛擬方法調用

有了對象的多態性以後,我們在編譯期,只能調用父類中聲明的方法,但在運行期,我們實際執行的是子類重寫父類的方法。

總結:編譯,看左邊;運行,看右邊。

多態性的注意事項

Java引用變量有兩個類型: 編譯時類型和運行時類型。 編譯時類型由聲明該變量時使用的類型決定, 運行時類型由實際賦給該變量的對象決定。 簡稱: 編譯時, 看左邊;運行時, 看右邊。

  • 若編譯時類型和運行時類型不一致, 就出現了對象的多態性(Polymorphism)

  • 多態情況下, “看左邊” : 看的是父類的引用(父類中不具備子類特有的方法);“看右邊” : 看的是子類的對象(實際運行的是子類重寫父類的方法)

  • 對象的多態 —在Java中,子類的對象可以替代父類的對象使用

    • 一個變量只能有一種確定的數據類型

    • 一個引用類型變量可能指向(引用)多種不同類型的對象

      Person p = new Student();
      Object o = new Person();//Object類型的變量o, 指向Person類型的對象
      o = new Student(); //Object類型的變量o, 指向Student類型的對象
      
  • 子類可看做是特殊的父類, 所以父類類型的引用可以指向子類的對象:向上轉型(upcasting)。

  • 一個引用類型變量如果聲明爲父類的類型,但實際引用的是子類對象,那麼該變量就不能再訪問子類中添加的屬性和方法

    Student m = new Student();
    m.school = “pku”; //合法,Student類有school成員變量
    Person e = new Student();
    e.school = “pku”; //非法,Person類沒有school成員變量
    

    屬性是在編譯時確定的,編譯時e爲Person類型,沒有school成員變量,因而編譯錯誤。

  • 對象的多態性,只適用於方法,不適用於屬性(編譯和運行都看左邊)

多態性的使用前提

① 類的繼承或者實現關係 ② 方法的重寫 ③向上轉型

多態性示例

方法聲明的形參類型爲父類類型,可以使用子類的對象作爲實參調用該方法

public class Test {
    public void method(Person e) {
        // ……
        e.getInfo();
    }
    public static void main(Stirng args[]) {
        Test t = new Test();
        Student m = new Student();
        t.method(m); // 子類的對象m傳送給父類類型的參數e
    }
}

虛擬方法調用(Virtual Method Invocation)

正常的方法調用

Person e = new Person();
e.getInfo();
Student e = new Student();
e.getInfo();

虛擬方法調用(多態情況下)

子類中定義了與父類同名同參數的方法,在多態情況下,將此時父類的方法稱爲虛擬方法,父類根據賦給它的不同子類對象,動態調用屬於子類的該方法。這樣的方法調用在編譯期是無法確定的。

Person e = new Student();
e.getInfo(); //調用Student類的getInfo()方法

編譯時類型和運行時類型

編譯時e爲Person類型,而方法的調用是在運行時確定的,所以調用的是Student類的getInfo()方法。 ——動態綁定

圖示

image-20200601084747489

前提

Person類中定義了welcome()方法,各個子類重寫了welcome()。

執行:

多態的情況下,調用對象的welcome()方法,實際執行的是子類重寫的方法。

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