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

Java 多態機制深度解析:對象類型多態、方法多態、向上轉型與動態分發

     編輯:Java 相關知識

多態核心:一個接口,多種實現

多態建立在繼承/實現基礎上,包含兩個維度:

  1. 對象類型多態:引用類型 ≠ 對象實際類型(向上轉型)。
  2. 方法多態(動態分發):調用覆寫方法時,執行對象實際類型的版本。

對象類型多態:向上轉型

class Animal { void sound() { System.out.println("Animal sound"); } }
class Cat extends Animal { @Override void sound() { System.out.println("Meow"); } }
class Dog extends Animal { @Override void sound() { System.out.println("Woof"); } }

// 向上轉型:子類對象賦值給父類引用
Animal a1 = new Cat();   // 編譯類型 Animal,運行類型 Cat
Animal a2 = new Dog();   // 編譯類型 Animal,運行類型 Dog
Animal a3 = new Animal(); // 編譯/運行均 Animal

instanceof 類型檢查

System.out.println(a1 instanceof Animal);  // true
System.out.println(a1 instanceof Cat);     // true
System.out.println(a1 instanceof Dog);     // false

// JDK 14+ 模式匹配
if (a1 instanceof Cat c) { c.sound(); }  // 同時檢查並轉型

兩大核心優勢

  1. 統一存儲:父類類型數組/集合存儲所有子類對象
  2. 統一參數/返回:方法簽名使用父類類型,接受任意子類

存儲示例

Animal[] zoo = new Animal[3];
zoo[0] = new Cat();
zoo[1] = new Dog();
zoo[2] = new Cat();
// 新增子類無需修改數組代碼

參數/返回示例

// 單一方法處理所有子類
public void feed(Animal a) { a.sound(); }

feed(new Cat());   // Meow
feed(new Dog());   // Woof

// 返回類型多態
public Animal create(String type) {
    return switch (type) {
        case "cat" -> new Cat();
        case "dog" -> new Dog();
        default -> new Animal();
    };
}

方法多態:動態分發機制

調用 a1.sound() 時:

  1. 編譯期:檢查 Animal 有 sound() 方法 → 通過。
  2. 運行期:JVM 根據對象實際類型(Cat)在方法表中查找並調用 Cat.sound()。

關鍵規則

  • 僅實例方法發生多態(static/private/final/構造器不參與)。
  • 方法簽名(名稱+參數列表)必須相同,返回類型兼容(协变返回)。
  • 訪問權限不能比父類更嚴格。

演示代碼

public class PolyDemo {
    public static void main(String[] args) {
        Animal a = new Animal();
        Animal c = new Cat();
        Animal d = new Dog();
        Animal c2 = new Cat(); // 向上轉型
        
        test(a);  // Animal sound
        test(c);  // Meow
        test(d);  // Woof
        test(c2); // Meow
    }
    
    static void test(Animal a) {
        a.sound(); // 動態分發
    }
}

/* 輸出:
Animal sound
Meow
Woof
Meow
*/

向下轉型:強制類型轉換


Animal a = new Cat();
// Cat c = a; // 編譯錯誤:父類引用不可隱式賦值給子類變量

if (a instanceof Cat) {
    Cat c = (Cat) a;  // 向下轉型:需運行期檢查
    c.catchMouse();   // 調用子類特有方法
}
  • 必須配合 instanceof 防 ClassCastException。
  • JDK 14+ if (a instanceof Cat c) 合二為一。
  • 濫用向下轉型違反開閉原則,優先用多態設計避免。

多態的代價與優化

  • 性能開銷:動態分發需查方法表(v-table),比靜態綁定慢。現代 JIT 內聯熱點虛方法後差異極小。
  • 內聯緩存:JVM 記錄調用點接收類型,單態/雙態調用點直接內聯。
  • final/sealed 類:編譯器/JIT 可確知無子類,直接靜態綁定。

sealed 類(JDK 17+):受控繼承的多態


public sealed class Shape permits Circle, Rectangle, Triangle { }
final class Circle extends Shape { }
final class Rectangle extends Shape { }
non-sealed class Triangle extends Shape { } // 允許繼續繼承
  • 限定可繼承的子類集合,編譯器強制檢查。
  • 模式匹配 switch 可窮盡性檢查,無需 default。
  • 兼具多態靈活性與封閉性保證。

設計原則:里氏替換原則 (LSP)

子類必須能替換父類且不破壞程序正確性。
違反例:Square extends Rectangle 導致 setWidth/setHeight 邏輯衝突。
解決:組合優於繼承,或重新設計繼承層次。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved