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

Java 繼承機制深度解析:基礎語法、訪問控制、方法重寫與多態實戰

     編輯:Java 相關知識

繼承核心概念

  • 定義:子類通過 extends 關鍵字繼承父類,獲得其非私有成員 (字段、方法、嵌套類)
  • 單繼承:Java 類只能直接繼承一個父類,但可多層繼承形成鏈
  • 傳遞性:孫類間接擁有祖父類成員
  • 目的:代碼復用、建立「是一種」關係、實現多態

語法與基本示例

父類:Employee (僱員)

public class Employee {
    private String name;
    private int id;
    private double salary;
    private String department;
    
    public Employee() {}
    public Employee(String name, int id, double salary, String department) {
        this.name = name; this.id = id; this.salary = salary; this.department = department;
    }
    
    // Getter/Setter...
    public void work() { System.out.println(name + " 正在工作..."); }
    
    @Override public String toString() {
        return "Employee{name='" + name + "', id=" + id + ", salary=" + salary + ", dept='" + department + "'}";
    }
}

子類:Manager (經理) - 擴展特有屬性

public class Manager extends Employee {
    private double bonus; // 績效獎金
    
    public Manager() { super(); }
    public Manager(String name, int id, double salary, String department, double bonus) {
        super(name, id, salary, department); // 必須首行調用父構造器
        this.bonus = bonus;
    }
    
    public double getBonus() { return bonus; }
    public void setBonus(double bonus) { this.bonus = bonus; }
    
    // 方法重寫:擴展工作行為
    @Override
    public void work() {
        super.work(); // 調用父類邏輯
        System.out.println("並審核團隊報告,發放獎金 " + bonus);
    }
    
    @Override
    public String toString() {
        return super.toString() + ", bonus=" + bonus;
    }
}

測試代碼

public class TestInheritance {
    public static void main(String[] args) {
        Manager mgr = new Manager("張三", 1001, 15000, "技術部", 5000);
        System.out.println(mgr); // 輸出含 bonus
        mgr.work(); // 調用重寫方法
        
        // 多態:父類引用指向子類對象
        Employee emp = new Manager("李四", 1002, 12000, "市場部", 3000);
        emp.work(); // 動態綁定:調用 Manager.work()
        // emp.bonus 編譯錯誤:父類引用不可訪問子類特有成員
    }
}

訪問控制與繼承

修飾符同類同包子類同包非子類異包子類異包非子類
private✅❌❌❌❌
default (包私有)✅✅✅❌❌
protected✅✅✅✅❌
public✅✅✅✅✅

關鍵規則

  • 子類**不可直接訪問**父類 private 成員,需通過 public/protected 方法間接訪問
  • protected 允許**異包子類**訪問,這是為繼承設計的關鍵修飾符
  • 構造器**不被繼承**,但子類構造器**必須**調用父類構造器 (super(...) 或隱式 super())

方法重寫 vs 重載

特性重寫重載
發生位置父子類之間同一類內部
方法簽名完全相同 (名稱、參數列表)名稱相同,參數列表不同
返回類型兼容 (协变返回类型 Java 5+)可不同
異常拋出子類異常 ⊆ 父類異常無限制
訪問權限子類 ≥ 父類 (不能縮小)無限制
綁定時機運行時動態綁定 (多態)編譯時靜態綁定

重寫規則口訣

兩同兩小一大:
方法名相同、參數列表相同
返回類型小於等於、拋出異常小於等於
訪問權限大於等於

錯誤示例

class Parent { public void doWork() {} }
class Child extends Parent {
    // ❌ 訪問權限縮小
    private void doWork() {} 
    
    // ❌ 拋出更大異常
    public void doWork() throws Exception {} // 父類無異常
    
    // ❌ 參數列表不同 -> 這是重載,非重寫
    public void doWork(int x) {}
}

字段隱藏

class Parent { String name = "Parent"; }
class Child extends Parent { String name = "Child"; }

public class Test {
    public static void main(String[] args) {
        Child c = new Child();
        System.out.println(c.name);        // "Child" (子類字段)
        System.out.println(((Parent)c).name); // "Parent" (父類字段)
        // 字段無多態,靜態綁定到引用類型
    }
}

多態實戰模式

1. 模板方法模式

abstract class DataProcessor {
    // 最終方法,定義算法骨架
    public final void process() {
        readData();
        doProcess(); // 子類實現
        writeData();
    }
    protected abstract void doProcess();
    private void readData() { /* 通用讀取 */ }
    private void writeData() { /* 通用寫入 */ }
}

class CsvProcessor extends DataProcessor {
    @Override protected void doProcess() { /* CSV 解析 */ }
}

2. 策略模式 (組合優於繼承)

interface PayStrategy { void pay(double amount); }
class Alipay implements PayStrategy { public void pay(double a) { /* ... */ } }
class WechatPay implements PayStrategy { public void pay(double a) { /* ... */ } }

class Order {
    private PayStrategy strategy;
    public void setPayStrategy(PayStrategy s) { this.strategy = s; }
    public void checkout(double amount) { strategy.pay(amount); }
}

Object 類常見重寫

方法默認行為重寫目的約定
toString()類名@哈希碼業務可讀描述建議所有實體重寫
equals(Object)引用相等 (==)業務鍵相等自反、對稱、傳遞、一致、非空
hashCode()對象地址衍生配合 equals 用於 Hash 集合equals 相等 ⇒ hashCode 相等
clone()淺拷貝深拷貝實現 Cloneable、拋 CloneNotSupportedException

equals 規範實現 (IDE 生成/Objects.equals)

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Employee that = (Employee) o;
    return id == that.id && 
           Double.compare(that.salary, salary) == 0 &&
           Objects.equals(name, that.name) &&
           Objects.equals(department, that.department);
}

@Override
public int hashCode() {
    return Objects.hash(id, name, salary, department);
}

final 關鍵字與繼承限制

  • final class:不可被繼承 (如 String, Integer)
  • final method:不可被重寫 (如 Object.getClass())
  • final field:初始化後不可修改,構造器/聲明處賦值

最佳實踐原則

  1. 里氏替換原則 (LSP):子類必須能替換父類而不破壞行為
  2. 組合優於繼承:優先考慮接口 + 組合 (策略、裝飾器),降低耦合
  3. 設計為繼承或禁止繼承:文檔化可重寫方法、敏感方法加 final
  4. 構造器不調用可重寫方法:父構造器調用被重寫方法時,子類字段尚未初始化
  5. @Override 註解:編譯期檢查重寫正確性,防止拼寫錯誤變重載

常見面試題

Q: 構造器能否被繼承?為什麼? 不能。構造器用於初始化本類字段,子類有自己的字段需自己的構造器初始化。子類構造器必須顯式/隱式調用父構造器完成父類部分初始化。
Q: 為什麼 Java 不支持多繼承?接口如何解決? 避免鑽石問題 (字段/方法衝突)。接口默認方法 (Java 8+) 可提供實現,類可實現多個接口實現多重行為復用。
Q: 父類靜態方法能否被重寫? 不能。靜態方法屬於類,不屬於實例,子類定義同名靜態方法稱為**隱藏**,調用由引用類型決定而非對象類型。
Q: super 和 this 的區別? this 當前對象引用;super 父類對象引用 (調用父構造器、訪問被隱藏父成員)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved