在Java里如何使用new关键字_对象创建流程解析

new创建对象需经类加载、内存分配、零值初始化与对象头设置、执行构造器四步;类加载含加载、验证、准备、解析、初始化五阶段,父类优先初始化;内存分配采用指针碰撞或空闲列表;构造器中先调父类构造器,再实例变量赋值、实例块、构造体。

在Java中,new关键字是创建对象最常用的方式,它背后涉及类加载、内存分配、初始化等多个步骤。理解这个流程,有助于排查空指针、静态块执行顺序、构造器调用异常等问题。

类加载检查(Class Lo

ading)

当JVM遇到new指令时,首先检查该类是否已被加载、解析和初始化。如果没有,会触发类加载过程:加载(从.class文件读入)、验证(确保字节码安全)、准备(为静态变量分配内存并设默认值)、解析(符号引用转直接引用)、初始化(执行方法,即static代码块和静态变量赋值)。

  • 若类尚未加载,new会阻塞,直到完成初始化
  • 同一个类在同一个类加载器下只会初始化一次
  • 父类会优先于子类被初始化(如果尚未初始化)

内存分配(Memory Allocation)

类加载完成后,JVM在堆中为新对象分配内存。分配方式取决于垃圾收集器和对象大小:

  • 指针碰撞(Bump the Pointer):适用于堆内存规整(如Serial、ParNew),移动空闲指针即可
  • 空闲列表(Free List):适用于内存不规整(如CMS),需从维护的列表中查找合适空间
  • 大对象可能直接进入老年代(受-XX:PretenureSizeThreshold影响)

初始化零值与设置对象头(Zeroing & Object Header)

内存分配后,JVM将该内存区域初始化为零值(不包括对象头),保证实例字段即使未显式赋值也有默认值(如int → 0Object → null)。同时设置对象头,包含:

  • Mark Word(存储哈希码、GC分代年龄、锁状态等)
  • Klass Pointer(指向类元数据的指针,用于确定对象属于哪个类)
  • 数组长度(仅数组对象有)

执行方法(构造器初始化)

最后,JVM调用对象的构造方法(即方法),按以下顺序执行:

  • 调用父类构造器(隐式或显式super()
  • 执行实例变量显式初始化(如private int x = 10;
  • 执行实例代码块({ ... }
  • 执行当前构造器方法体

注意:此时对象才真正“可用”;在构造器执行完毕前,若发生逃逸(如将this发布到其他线程),可能导致看到未完全初始化的对象状态。