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

Java 核心概念深度解析:繼承、多態、重載與重寫

     編輯:Java 程式設計入門

前言

在 Java 物件導向程式設計中,繼承、多態、方法重載與重寫是四大核心支柱。它們不僅構成了類別之間關係的基石,更決定了程式碼的可擴展性與維護性。本文將系統梳理這四大概念的定義、實現機制、關鍵差異與最佳實踐,並輔以程式碼範例幫助深度理解。

一、繼承:類別複用的基石

1.1 什麼是繼承?

繼承允許在現有類別(父類別/基類別)基礎上,透過新增方法或重新定義既有方法(即重寫)來建立新類別(子類別/衍生類別)。Java 中所有類別隱含繼承自 java.lang.Object,若未顯式指定 extends,編譯器會自動補上。

1.2 三種類別類型與繼承規則

  • 具體類別:class 定義,無抽象方法。
  • 抽象類別:abstract class 定義,可含抽象方法。
  • 介面:interface 定義,方法預設為 public abstract。

繼承關鍵字規則:

子類型繼承類別繼承抽象類別實作介面
具體類別extendsextendsimplements
抽象類別extendsextendsimplements
介面——extends

注意:extends 與 implements 不可互換。介面只能繼承介面,支援多重繼承;類別與抽象類別僅支援單一繼承(類別或抽象類別二擇一),但可實作多個介面。

1.3 繼承 vs 組合:複用策略抉擇

繼承屬「is-a」關係(如「黃種人是人類」),組合屬「has-a」關係(如「汽車有引擎」)。若新類別與舊類別無包含關係,組合更佳,因能避免破壞封裝、降低耦合。組合範例:

public class Sub {
    private Parent p = new Parent();
    public void doSomething() {
        p.method(); // 透過委派複用
    }
}

兩種方式皆屬增量式開發,不修改原始碼,降低引入 Bug 風險,適合維護既有系統。

二、多態:動態綁定的藝術

2.1 核心定義

多態指「一種型別,多種行為」。同一介面(或父類別)引用指向不同子類別物件時,呼叫同一方法會呈現不同行為。其基礎是繼承,實現機制是後期綁定(動態綁定):執行期根據物件實際型別決定呼叫哪個方法版本。

2.2 綁定機制對比

  • 前期綁定(靜態綁定):編譯期決定,適用 static、final、private 方法。
  • 後期綁定(動態綁定):執行期決定,其餘所有方法。多態即建立於此。

2.3 經典範例:汽車銷售系統

interface Car {
    String getName();
    int getPrice();
}

class BMW implements Car { ... }
class CheryQQ implements Car { ... }

class CarShop {
    private int money = 0;
    public void sellCar(Car car) { // 參數為介面型別
        money += car.getPrice();   // 動態綁定,自動調用對應實作
    }
}

新增車型只需實作 Car 介面,CarShop 完全無需修改,完美展現「開放封閉原則」。

三、方法重載 vs 重寫:兩大易混淆概念

3.1 方法簽名

方法簽名包含:方法名稱 + 參數列表(數量、型別、順序)。不包含回傳型別、存取修飾符、abstract/static/final 等關鍵字。

3.2 重載

  • 發生於同一個類別內。
  • 方法名相同,參數列表不同(型別、數量或順序至少一項不同)。
  • 回傳型別、修飾符可同可不同。
  • 屬靜態綁定,編譯期根據參數決定呼叫哪個版本。

3.3 重寫

  • 發生於繼承體系中,子類別重新定義父類別方法。
  • 方法簽名完全相同(名稱、參數列表一致)。
  • 回傳型別需相容(Java 5 起支援共變返回型別)。
  • 存取權限不能比父類別更嚴格。
  • 屬動態綁定,執行期根據物件實際型別分派。
  • 是實現多態的必要條件。

3.4 建構子特殊規則

  • 建構子可重載(同類別多種參數列表)。
  • 建構子不可重寫(子類別無法定義相同簽名建構子),但可透過 super() 呼叫父類別建構子。

四、C++ 視角的深度補充:隱藏、覆蓋與虛函數表

原文包含大量 C++ 範例,闡述「隱藏」與「覆蓋」的微妙差異。核心結論:

  • 衍生類別定義同名函數(無論參數是否相同),基類別所有同名重載版本均被隱藏。
  • 若需保留基類別重載版本,需在衍生類別以 using Base::fun; 顯式引入。
  • virtual 關鍵字決定是「覆蓋」(多態)還是「隱藏」:有 virtual 且簽名相同 → 覆蓋;無 virtual → 隱藏。
  • 虛函數表(vtable)機制:覆蓋會替換 vtable 中函數指標;新增重載僅屬衍生類別靜態部分,基類別指標無法多態調用。

五、String 物件建立與字串池機制

5.1 經典面試題

String str = new String("abc"); // 建立幾個物件?

答案:2 個。"abc" 在字串池建立 1 個;new String(...) 在堆積建立第 2 個,str 指向堆積物件。

5.2 字串池運作原理

  • 字串常數(雙引號語法)編譯期進入字串池,相同內容共用同一物件。
  • new String() 每次都在堆積建立新物件,不進池。
  • intern() 可手動將堆積字串放入池中(若池中已有相同值則返回池中引用)。
  • 編譯期常量折疊:"ab" + "cd" → "abcd" 直接進池;含變數的連接則在執行期建立,不進池。

5.3 記憶體佈局

  • 堆疊:儲存基本型別與物件引用。
  • 堆積:儲存物件實體(含 char[] value)。
  • 字串池:屬方法區/堆積一部分,儲存字串常數引用,實現共享。

六、總結與最佳實踐

  1. 優先使用組合而非繼承,除非確立明確 is-a 關係。
  2. 善用多態面向介面編程,降低模組耦合。
  3. 重寫時加上 @Override 註解,編譯器可攔截簽名錯誤。
  4. 字串操作優先用字面常量與 StringBuilder,避免無謂 new String()。
  5. 理解靜態/動態綁定差異,正確預測方法分派行為。

掌握這四大核心概念,是寫出健壯、可擴展 Java 程式的關鍵。建議結合原始碼除錯、反編譯觀察字節碼,深化對 JVM 方法分派機制的理解。

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