繼承是面向對象三大特性之一,實現代碼復用與多態基礎。本文通過 Employee / Manager 經典案例,深度講解 extends 關鍵字、super 調用父構造器、方法重寫規則、向上轉型與動態分派機制。
import java.util.Date;
import java.util.GregorianCalendar;
public class Employee {
private String name;
private double salary;
private Date hireDay;
public Employee(String name, double salary, int year, int month, int day) {
this.name = name;
this.salary = salary;
GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day);
this.hireDay = calendar.getTime();
}
public String getName() { return name; }
public double getSalary() { return salary; }
public Date getHireDay() { return hireDay; }
public void raiseSalary(double byPercent) {
double raise = salary * byPercent / 100;
salary += raise;
}
}
public class Manager extends Employee {
private double bonus;
// 子類構造器必須調用父類構造器
public Manager(String name, double salary, int year, int month, int day) {
super(name, salary, year, month, day); // 必須是第一句
this.bonus = 0;
}
public void setBonus(double bonus) { this.bonus = bonus; }
// 重寫 getSalary:基礎薪資 + 獎金
@Override
public double getSalary() {
double baseSalary = super.getSalary(); // 調用父類實現
return baseSalary + bonus;
}
}
public class TestInheritance {
public static void main(String[] args) {
Manager boss = new Manager("Boss", 80000, 1987, 12, 15);
boss.setBonus(5000);
Employee[] staff = new Employee[3];
staff[0] = boss; // 向上轉型:Manager → Employee
staff[1] = new Employee("Emp1", 50000, 1989, 10, 1);
staff[2] = new Employee("Emp2", 40000, 1990, 3, 15);
// 多態:同樣調用 getSalary(),運行期根據實際對象類型分派
for (Employee e : staff) {
System.out.println("name=" + e.getName() + ", salary=" + e.getSalary());
}
/* 輸出:
name=Boss, salary=85000.0 (80000 + 5000 bonus)
name=Emp1, salary=50000.0
name=Emp2, salary=40000.0
*/
}
}
class Child extends Parentjava.lang.Object| 用法 | 語法 | 場景 | 規則 |
|---|---|---|---|
| 調用父構造器 | super(args) | 子類構造器首行 | 必須第一句;無則隱式 super() 調用父無參構造 |
| 調用父類方法 | super.method() | 重寫中復用父邏輯 | 可在任意非靜態方法中使用 |
| 訪問父類字段 | super.field | 子類同名字段遮蔽時 | 較少用,建議避免同名字段 |
new Manager("Boss", 80000, 1987, 12, 15)
→ Manager 構造器
→ super(name, salary, year, month, day) // 顯式調用
→ Employee 構造器初始化 name, salary, hireDay
→ Manager 初始化 bonus = 0
→ 返回 Manager 實例
鐵律:子類構造器必須直接或間接調用父類構造器,否則編譯錯誤。
protected → public ✅,public → protected ❌private 方法不可見故不存在重寫Employee e = new Manager(); // 向上轉型
e.getSalary(); // 編譯期看 Employee.getSalary,運行期調用 Manager.getSalary
e.field 總是訪問聲明類型的字段| 誤區 | 正確理解 |
|---|---|
| 子類繼承父類私有字段 | 私有字段不可見,但通過父類 public/protected 方法間接訪問 |
| 構造器可繼承 | 構造器不繼承,子類必須自行定義並調用 super() |
| 靜態方法可重寫 | 靜態方法隱藏,非重寫,無多態 |
| 向下轉型無風險 | 需 instanceof 守衛,否則 ClassCastException |
extends 建立繼承,子類擴展父類功能super() 調用父構造器必須在子構造器首行@Override 保證正確性instanceof