首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 多態核心筆記:繼承、方法覆蓋、向上轉型與調用規則完全圖解

     編輯:Java 相關知識

多態是面向對象三大支柱中最具威力、也最易混淆的一環。本文從「三大前提」切入,通過代碼示例、調用規則表、內存模型圖解,徹底講透多態的本質與實戰規則,助你告別「父類引用指向子類對象後調用誰」的困惑。

多態三大前提(缺一不可)

  1. 繼承:子類 extends 父類(或實現接口),建立「is-a」關係。
    例:class Bird extends Animal,鳥擁有動物通用屬性(吃、睡),但具體吃什麼、怎麼吃由子類決定。
  2. 方法覆蓋:子類重寫父類方法(同名、同參數、同/卸返回類型、異常不擴大、訪問權限不縮小)。
    父類定義通用契約,子類提供具體實現。
  3. 父類引用指向子類對象(向上轉型):Animal a = new Bird();
    編譯期看左邊(父類),運行期看右邊(子類實際對象)。

向上轉型與向下轉型

最佳實踐:向下轉型前用 instanceof 守護:if (animal instanceof Bird) ((Bird) animal).fly();。

方法調用鐵律:編譯看左邊,運行看右邊

class Animal { void eat() { sysout("動物吃東西"); } }
class Bird extends Animal { void eat() { sysout("鳥吃蟲子"); } void fly() { sysout("飛"); } }

Animal a = new Bird();
a.eat();  // 輸出:「鳥吃蟲子」—— 運行期動態綁定到 Bird.eat()
a.fly();  // 編譯錯誤!Animal 無 fly() 方法

三大調用規則總結表

轉型方向語法安全性用途
向上Parent p = new Child();自動、安全多態參數傳遞、集合存儲、接口編程
向下Child c = (Child) parentRef;需強制、可能拋 ClassCastException調用子類特有方法/字段

內存模型視角:為什麼能動態綁定?

  • 每個類加載時,方法區生成方法表,記錄方法簽名 → 字節碼入口地址。
  • 子類繼承父類方法表,覆蓋方法時替換入口地址指向子類字節碼。
  • 對象頭包含指向類元數據的指針(Klass Point)。
  • 調用 a.eat() 時:
    ① 讀取對象頭指針定位到 Bird 類元數據
    ② 在方法表查找 eat 入口
    ③ 跳轉執行 Bird.eat() 字節碼

字段不具備多態:靜態綁定

class Parent { int x = 1; }
class Child extends Parent { int x = 2; }

Parent p = new Child();
System.out.println(p.x); // 輸出 1!字段按編譯期類型綁定(Parent.x)

結論:只有非 static、非 final、非 private的實例方法具有多態性。字段、靜態方法、私有方法、構造器均為靜態綁定。

實戰陷阱:構造器中調用覆蓋方法

class Base {
    Base() { init(); } // 構造器調用
    void init() { sysout("Base init"); }
}
class Derived extends Base {
    int x = 10;
    Derived() { sysout("Derived init, x=" + x); }
    @Override void init() { sysout("Derived init, x=" + x); } // x 尚未初始化!
}
new Derived(); 
/* 輸出:
Derived init, x=0  ← 危險!字段默認值
Derived init, x=10
*/

鐵律:構造器中不可調用可覆蓋方法(直接或間接)。將方法標記 final 或 private,或移至初始化塊/工廠方法中。

總結

多態本質:同一接口,多種實現,運行期動態綁定。掌握三大前提、調用鐵律、字段無多態、構造器陷阱,即可在設計中正確應用「面向接口編程」、「策略模式」、「模板方法模式」等經典模式。記住:Animal a = new Bird() 時,a 能做的只有 Animal 定義的事,但怎麼做由 Bird 決定。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
場景調用哪個方法?原理
父類有方法,子類覆蓋子類方法動態綁定:JVM 根據實際對象類型查找方法表
父類有方法,子類未覆蓋父類方法繼承鏈向上查找,找到首個實現
子類特有方法(父類無)無法直接調用編譯期類型無此方法,需向下轉型