首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Java 繼承機制深度解析:父類私有字段在子類實例中的內存佈局與訪問原理

     編輯:程式設計疑難解答

核心問題

Java 規定子類不繼承父類的 `private` 字段,但 `new Child()` 時,堆上的子類對象是否為父類 `private` 字段分配內存?若不分配,子類調用繼承的 `public getA()` 時如何讀取到父類 `private int a` 的值?

結論先行

子類實例在堆中完整包含父類所有非靜態字段(包括 private),只是編譯器禁止子類代碼直接按名訪問。 內存佈局中父類字段與子類字段連續存放,訪問通過父類的公共方法間接實現。

內存佈局圖解

Child 對象內存結構:
+------------------+
| Father 部分      |
|  - private int a |  <-- 佔用 4 字節
|  - private int b |
|  - private int c |
+------------------+
| Child 部分       |
|  - private int c |  <-- 子類自己的 c,覆蓋概念僅在編譯期
+------------------+

驗證代碼

class Father {
    private int a = 3;
    private int b = 3;
    private int c = 3;
    public Father(int b) { this.b = b; }
    public int getA() { return a; }
    public void setA(int a) { this.a = a; }
    // ... 其他 getter/setter
}

class Child extends Father {
    private int c;  // 子類自己的 c
    public Child() { super(0); }
    public Child(int b, int c) { super(b); this.c = c; }
    public int getC() { return c; }  // 返回子類的 c
    // 未重寫 getA(),繼承父類的 getA()
}

public static void main(String[] args) {
    Child c1 = new Child();
    Child c2 = new Child(3, 5);
    System.out.println("c1.a=" + c1.getA() + " c1.b=" + c1.getB() + " c1.c=" + c1.getC());
    // 輸出: c1.a=3 c1.b=0 c1.c=0
    c2.setA(4);
    c2.setC(c2.getC() + 1);
    System.out.println("c2.a=" + c2.getA() + " c2.c=" + c2.getC());
    // 輸出: c2.a=4 c2.c=6
}

關鍵觀察

  1. `c1.getC()` 返回 0(子類 `c` 默認值),而非父類 `c=3`,證明子類**擁有自己的 `c` 字段**,父類 `c` 被遮蔽但仍存在內存中。
  2. `c2.setA(4)` 修改的是父類 `private a`,`c1.getA()` 仍為 3,證明每個實例擁有獨立的父類字段副本。
  3. 調試器查看 `c2` 對象結構,可見 `a`、`b` 位於 `Father` 部分,`c` 位於 `Child` 部分。

方法調用與棧幀

調用 `c2.getA()` 時:

  1. 主線程棧壓入 `main` 幀。
  2. 調用 `getA()` 壓入 `Father.getA` 幀,`this` 指向 `c2` 對象。
  3. 方法體執行 `return a;`,直接讀取對象頭偏移量對應的內存位置(父類 `a` 的槽位)。
  4. 彈棧返回值。

整過程**無需在棧中創建局部變量副本**;`a` 始終駐留在堆對象內存中。

官方規範對應

《Java Language Specification》§8.2: "The non-private fields, methods, and constructors of a class are inherited by its subclasses... Private members are not inherited."

「不繼承」僅指**編譯期可見性**,不代表**運行期內存不存在**。

總結

  • 子類對象內存 = 父類所有實例字段 + 子類實例字段。
  • `private` 字段通過父類 `public/protected` 方法間接訪問,屬於封裝機制體現。
  • 理解此機制有助於正確設計繼承體系、避免字段遮蔽導致的邏輯錯誤。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved