Java继承关系中的内存分配

在Java继承关系中,内存分配与类的加载、对象创建过程紧密相关,核心逻辑如下:

 

一、类加载阶段的内存布局

 

1. 静态区域分配(方法区)

- 父类和子类的静态变量( static )、静态代码块、类元数据(Class对象) 会被加载到JVM的方法区(JDK8后为元空间)。

- 顺序:先加载父类静态成员,再加载子类静态成员。

- 示例:

class Parent {

    static { System.out.println("父类静态代码块"); }

    static int staticVar = 10;

}

class Child extends Parent {

    static { System.out.println("子类静态代码块"); }

    static int staticVar = 20;

}

 

 

当首次使用 Child 类时,先加载父类 Parent 的静态成员,再加载子类 Child 的静态成员。

 

二、对象创建时的内存分配(堆内存)

 

1. 对象内存布局

- 子类对象在堆中分配的内存包含:

- 父类非静态成员(属性、方法引用)。

- 子类自身非静态成员。

- 本质:子类对象是“父类对象的扩展”,父类成员作为子类对象的一部分存在。

2. 构造函数执行与内存初始化

- 执行顺序:

1. 父类构造函数优先执行(默认调用无参构造 super() ),为父类非静态成员分配内存并初始化。

2. 再执行子类构造函数,为子类非静态成员分配内存并初始化。

- 示例:

class Parent {

    int parentField = 10;

    public Parent() {

        System.out.println("父类构造函数,parentField = " + parentField);

    }

}

class Child extends Parent {

    int childField = 20;

    public Child() {

        System.out.println("子类构造函数,childField = " + childField);

    }

}

 

 

创建 Child 对象时,先初始化父类的 parentField 为10,再初始化子类的 childField 为20。

 

三、引用类型与内存指向

 

1. 向上转型时的内存指向

- 当用父类引用指向子类对象(如 Parent p = new Child(); ):

- 引用变量 p 在栈中存储子类对象的地址。

- JVM通过对象头的类型信息确定实际对象类型(子类 Child ),调用方法时按子类实现执行(多态)。

2. 内存占用示例

- 假设父类 Parent 有属性 a 和 b ,子类 Child 新增属性 c 和 d ,则 Child 对象在堆中的内存布局大致如下:

[Parent对象部分] | [Child对象部分]

-----------------|-----------------

a: 数据 | c: 数据

b: 数据 | d: 数据

-----------------|-----------------

 

 

四、关键要点总结

 

- 类加载顺序:父类静态成员 → 子类静态成员。

- 对象创建顺序:父类非静态成员初始化 → 父类构造函数 → 子类非静态成员初始化 → 子类构造函数。

- 内存复用:子类对象包含父类对象的所有非静态成员,避免重复分配内存,体现继承的代码复用性。

- 多态的内存本质:引用变量指向子类对象,但编译时受父类类型限制,运行时根据实际对象类型调用方法(动态绑定)。

 

示例验证

 

通过以下代码可观察继承关系的内存分配顺序:

 

class Base {

    static { System.out.println("Base静态块"); }

    { System.out.println("Base实例块"); }

    Base() { System.out.println("Base构造函数"); }

}

 

class Sub extends Base {

    static { System.out.println("Sub静态块"); }

    { System.out.println("Sub实例块"); }

    Sub() { System.out.println("Sub构造函数"); }

}

 

public class InheritanceMemory {

    public static void main(String[] args) {

        new Sub(); // 输出顺序:Base静态块 → Sub静态块 → Base实例块 → Base构造 → Sub实例块 → Sub构造

    }

}

 

 

理解继承的内存分配有助于掌握多态、构造函数调用等核心机制,若有具体疑问可以进一步探讨哦~

你可能感兴趣的:(java)