子类对象在堆中只占一块连续内存,包含对象头、父类非静态字段和子类自身非静态字段,按继承链顺序线性排列;同名字段共存且通过偏移量区分,private字段也分配空间但受访问控制限制。

父类成员变量就存在子类对象的堆内存里,不是额外开一块空间,也不是复制一份,而是作为子类对象内存块的前缀部分连续排布。
子类对象只占一块堆内存
Java中创建子类实例时,JVM只在堆中分配一个连续内存块。这个块包含三部分:对象头、父类非静态字段、子类自身非静态字段。比如class A { int id; }和class B extends A { String name; },new B()生成的对象内存结构是:[对象头][id][name]。父类字段不单独成对象,也不在方法区或栈中——它们就在这个堆块里。
字段按继承链顺序线性排列
- 对象头在最前面,含Mark Word和类型指针(指向B.class)
- 紧接着是Object类字段(如有),然后是直接父类A的字段,再是B自己的字段
- 每个字段位置由编译期确定偏移量:比如int占4字节,String引用占4或8字节(取决于压缩指针),访问
this.id就是读取对象起始地址+对象头大小后的第1个int位置
同名字段不会覆盖,而是共存于同一对象
若A和B都声明了int num,子类对象中实际有两个num:一个在父类字段区域,一个在子类字段区域。调用this.num读取的是子类偏移处的值,super.num读取的是父类偏移处的值。它们物理上相邻但逻辑归属不同,编译器靠偏移量区分,不靠运行时查找。
private字段也分配空间,只是不可直接访问
即使父类字段被声明为private int secret,它依然会出现在子类对象的堆内存中,位置仍在父类字段段。子类不能写super.secret,但可通过父类提供的public getter间接读取——因为该字段真实存在且已初始化,只是访问权限受限。这不是冗余,而是封装与内存布局的解耦。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











