从内存层面分析Java 类加载与对象创建的完整过程

在Java中,类的加载、链接与初始化的过程是对象创建的基础。类的加载遵循双亲委派模型,而对象的创建则涉及内存分配和变量初始化。本文将详细介绍这一过程,并配合代码示例说明何时赋予默认值,何时赋予初始值,以及类加载的懒加载和静态成员变量的处理。

一、类加载过程
  1. 加载(Loading)
    当我们首次使用某个类时,JVM 会通过类加载器将.java文件编译后的 .class 文件加载到内存中。在加载过程中,类的字节码被读取进来,并在运行时生成该类的 Class 对象。

  2. Linking(链接)

  • Verification(验证):检查类的字节码是否符合 JVM 规范,确保类的格式正确(如检查 class 文件开头是否为 CAFEBABE)。
  • Preparation(准备):为类的静态变量分配内存,并将静态变量初始化为默认值(如 int 类型为 0,引用类型为 null)。
  • Resolution(解析):将符号引用转换为直接引用,比如将方法、字段等符号化引用解析为内存地址。
  1. 初始化(Initialization)
    执行类的静态代码块和为静态变量赋予代码中指定的初始值。例如,如果静态变量在声明时被赋值,或者在静态代码块中被赋值,这些操作会在初始化阶段完成。
二、对象的创建过程

当我们使用 new 关键字创建对象时,经历以下步骤:

  1. 为对象分配内存
    JVM 会在堆内存中为新对象分配内存。此时,成员变量被赋予默认值,例如 int 被初始化为 0,引用类型变量被初始化为 null

  2. 调用构造器
    JVM 执行构造方法中的逻辑,对成员变量赋予初始值。构造方法的第一行会隐式调用父类的构造方法(super())。

  3. 成员变量的初始化顺序
    在构造方法执行之前,成员变量按声明顺序依次赋初始值。例如:

    • 声明时赋值:int i = 8;
    • 初始化块和构造器对成员变量的赋值顺序也会被执行。
三、代码示例:类加载和对象创建
class Example {
    // 静态变量
    private static int staticVar = initializeStaticVar();
    private static int staticVarDefault;

    // 实例变量
    private int instanceVar = 8;
    private String instanceVarDefault;

    // 静态代码块
    static {
        System.out.println("Static block executed");
        staticVarDefault = 10;
    }

    // 实例代码块
    {
        System.out.println("Instance block executed");
        instanceVarDefault = "Hello";
    }

    // 构造方法
    public Example() {
        System.out.println("Constructor executed");
    }

    private static int initializeStaticVar() {
        System.out.println("Static variable initialized");
        return 5;
    }

    public static void main(String[] args) {
        System.out.println("Before creating object");
        Example example = new Example();
        System.out.println("After creating object");

        System.out.println("staticVar: " + Example.staticVar); // 5
        System.out.println("staticVarDefault: " + Example.staticVarDefault); // 10
        System.out.println("instanceVar: " + example.instanceVar); // 8
        System.out.println("instanceVarDefault: " + example.instanceVarDefault); // Hello
    }
}
输出解释
  1. 静态成员变量
    staticVar 被初始化时,initializeStaticVar() 方法首先被调用,输出 “Static variable initialized”,然后在静态代码块中 staticVarDefault 被赋值为 10。静态变量的初始化在类加载时完成。

  2. 实例成员变量
    Example 类对象被创建时,instanceVar 直接赋初始值 8instanceVarDefault 在实例代码块中被赋值为 "Hello"

  3. 类加载顺序
    当程序执行 Example example = new Example(); 时,类加载器首先加载 Example 类,静态变量 staticVarstaticVarDefault 被赋值。接着,创建实例时,实例代码块和构造器依次执行。

四、懒加载与静态变量赋值

懒加载 是指类在实际使用时才会加载,而不是在程序启动时立即加载。例如,当 Example 类首次被引用时(在 main 方法中实例化 Example),它才会被加载。

静态变量赋值 的时机如下:

  • 静态变量的默认值会在“准备阶段”赋值。例如,int 类型的静态变量会被初始化为 0
  • 静态变量的初始值会在“初始化阶段”赋值,例如在类的静态代码块或静态变量声明中赋值。
五、总结
  1. 类的加载遵循了双亲委派模型,经历加载、验证、准备、解析和初始化五个阶段。
  2. 在类加载过程中,静态变量首先被赋默认值,之后在初始化阶段被赋予指定的初始值。
  3. 对象的创建分配内存,并为实例变量赋默认值。在构造方法执行前,实例变量按声明顺序被赋初始值。
  4. 静态变量的初始化是在类加载时完成的,实例变量的初始化是在对象创建时完成的。

这种类加载与对象创建的机制确保了 Java 程序的稳定性与灵活性,同时也为我们提供了理解 JVM 运作方式的基础。


今天的内容就到这里啦,如果大家有任何问题欢迎评论区留言交流!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值