父類 Father 定義 private int a = 1 及 getA()/setA();子類 A、B 分別定義 private int a = 2/3 並重寫 getA()/setA()。測試代碼:
Father fa = new A(); Father fb = new B(); System.out.println(fa.getA()); // 2 System.out.println(((A)fa).getA()); // 2 System.out.println(fb.getA()); // 3 System.out.println(((B)fb).getA()); // 3
輸出均為子類字段值。但若子類 不重寫 方法,輸出卻變為父類值 1。這背後機制是什麼?
private 字段不可繼承,子類聲明同名字段屬於「遮蔽」,父子類各自擁有獨立的 a。引用類型決定訪問哪個 a:父類引用訪問父類 a,子類引用訪問子類 a。
getA() 為非私有實例方法,子類重寫後,JVM 根據對象實際類型(A 或 B)動態分派到子類方法。子類方法內部 return a; 訪問的是子類自己的字段 a。
| 場景 | 子類重寫方法 | 調用 fa.getA() | 解釋 |
|---|---|---|---|
| 場景一 | 是 | 子類值(2/3) | 動態分派到子類方法,子類方法讀子類字段 |
| 場景二 | 否 | 父類值(1) | 繼承父類方法,父類方法讀父類字段 |
「字段看引用類型,方法看對象類型」——這句口訣精準概括了 Java 繼承中字段遮蔽與方法重寫的核心差異。掌握此點,即可避開繼承層級中的常見坑。