Java子类对象在堆中仅占一块连续内存,父类非静态字段作为前缀嵌入其中,按继承链顺序平铺排列;static成员独立存于方法区,不占用实例空间。

Java子类对象在堆内存中只占**一块连续空间**,父类的非静态成员变量不是独立存在、也不是“复制一份”,而是作为子类对象内存布局的**前缀部分直接嵌入其中**。
字段按继承链顺序平铺排列
子类实例的内存结构是扁平化的,字段从上到下严格按继承层级排布:
- 对象头(Mark Word + 类型指针)
- 最顶层父类(如 Object)的非静态字段
- 中间父类的非静态字段
- 子类自身声明的非静态字段
例如:class A { int id; } 和 class B extends A { String name; },new B() 在堆中实际布局为:[Header][id][name] —— 没有单独的 A 对象,只有这一整块内存。
private 字段也占用空间
即使父类字段被 private 修饰,它依然会出现在子类对象的实例数据区域中:
立即学习“Java免费学习笔记(深入)”;
- 子类无法通过
super.xxx或this.xxx直接访问该字段 - 但字段本身仍占内存,且可通过父类的 public/protected 方法间接读写
- 反编译字节码(
javap -private)可验证:父类 private 字段出现在子类字段列表里
static 成员不参与对象布局
静态变量、静态方法、类元数据都存放在方法区(JDK 8+ 是元空间),和堆中的对象实例完全分离:
- 它们属于类,不属于任何对象实例
- 子类继承 static 成员,只是获得访问权限,不会在每个子类对象里重复分配空间
- 哪怕创建 1000 个子类实例,static 变量在内存中仍只有 1 份
super 不是另一个对象,只是访问视角
super 关键字不是指向一个独立的父类对象,而是 JVM 提供的一种**字段与方法访问语法糖**:
-
super.num表示访问当前对象内存中属于父类定义的那一份num -
this.num若与父类同名,则访问子类自己定义的那份(二者共存,互不覆盖) -
super.getClass()返回的仍是子类类型(如Son.class),证明堆中只有一个对象


















