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

深度解析 Java 子型別多態:從類型理論看繼承與介面的本質

     編輯:Java 相關知識

多態的四大分類

依據 Luca Cardelli 與 Peter Wegner 的經典分類,多態可分為兩大類四小類:

大類小類說明Java 支援度
特定多態強制隱式型別轉換(如 double + int → double + double)支援
重載同名稱表達不同意義(方法多載、運算子多載)支援方法多載,不支援使用者定義運算子多載
通用多態參數泛型程式設計(如 List<T>),單一演算法適用多型別Java 5 前不支援真正參數多態,僅用 Object 模擬
包含子型別多態,透過繼承層級實現核心支援,即「介面對介面程式設計」的基石

本文聚焦於 包含多態(子型別多態),探討其類型導向的本質。

類型導向觀點:引用與物件的分離

範例類別階層

public class Base {
    public String m1() { return "Base.m1()"; }
    public String m2(String s) { return "Base.m2(" + s + ")"; }
}
interface IType {
    String m2(String s);
    String m3();
}
public class Derived extends Base implements IType {
    public String m1() { return "Derived.m1()"; }      // 覆寫
    public String m3() { return "Derived.m3()"; }      // 實作介面
}
public class Derived2 extends Derived {
    public String m2(String s) { return "Derived2.m2(" + s + ")"; } // 覆寫
    public String m4() { return "Derived2.m4()"; }     // 新增
}
public class Separate implements IType {               // 無繼承關係
    public String m1() { return "Separate.m1()"; }
    public String m2(String s) { return "Separate.m2(" + s + ")"; }
    public String m3() { return "Separate.m3()"; }
}

引用視窗概念

當宣告 Derived2 d2 = new Derived2();,d2 擁有完整視窗,可見 m1()~m4()。

當以基類別引用指向同一物件:Base b = d2;,b 的視窗縮小,僅能看到 Base 定義的 m1()、m2(),但實際執行的程式碼仍由物件真實型別(Derived2)決定。

d2.m1(); // "Derived.m1()"
b.m1();  // "Derived.m1()"  ← 同一物件,同一行為

d2.m3(); // "Derived.m3()"
b.m3();  // 編譯錯誤:Base 視窗看不到 m3()

關鍵結論

  • 物件決定行為(執行期):方法調用的實際程式碼由物件的真實類別決定
  • 型別決定可見性(編譯期):引用的靜態型別決定可呼叫哪些方法
  • 多態 = 型別一致性 + 動態派發:編譯器保證引用指向的物件具備所需能力,執行期再選擇具體實作

介面與多型別繼承的威力

IType 引用可同時指向 Derived2 與 Separate 兩個完全無繼承關係的物件:

IType it1 = new Derived2();
IType it2 = new Separate();
it1.m3(); // "Derived.m3()"
it2.m3(); // "Separate.m3()"

這展示了 Java 介面實現 多型別繼承 而避免了 C++ 多重繼承的菱形繼承問題:

  • 介面定義「契約」(型別層級),完全脫離實作細節
  • 任意類別實作介面即成為該子型別
  • 單一物件可同時擁有多個介面型別身分

「物件介面」vs「型別介面」的觀念釐清

傳統觀點常混淆「物件擁有的所有 public 方法」與「引用型別所暴露的介面」。

  • 物件介面:物件完整的 public 方法集合(實作導向)
  • 型別介面:引用靜態型別所承諾的方法集合(契約導向)

多態的本質在於 透過型別介面操作物件,將「做什麼」(契約)與「怎麼做」(實作)分離。介面型別決定舞伴與舞名,具體類別設計舞步。

實務啟示

  1. 介面導向設計:參數、回傳值、欄位宣告盡量使用介面型別
  2. 里氏替換原則:子型別必須能無縫替換基型別,不破壞契約
  3. 組合優於繼承:利用介面注入實現策略模式等,比深層繼承更彈性
  4. 避免破壞多態:不要在子類別新增基類別無定義的 public 方法並期望透過基類別引用呼叫
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved