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

在Java中,new关键字是创建对象最常用的方式,它背后涉及类加载、内存分配、初始化等多个步骤。理解这个流程,有助于排查空指针、静态块执行顺序、构造器调用异常等问题。
类加载检查(Class Loading)
当JVM遇到new指令时,首先检查该类是否已被加载、解析和初始化。如果没有,会触发类加载过程:加载(从.class文件读入)、验证(确保字节码安全)、准备(为静态变量分配内存并设默认值)、解析(符号引用转直接引用)、初始化(执行方法,即static代码块和静态变量赋值)。
- 若类尚未加载,
new会阻塞,直到完成初始化 - 同一个类在同一个类加载器下只会初始化一次
- 父类会优先于子类被初始化(如果尚未初始化)
内存分配(Memory Allocation)
类加载完成后,JVM在堆中为新对象分配内存。分配方式取决于垃圾收集器和对象大小:
- 指针碰撞(Bump the Pointer):适用于堆内存规整(如Serial、ParNew),移动空闲指针即可
- 空闲列表(Free List):适用于内存不规整(如CMS),需从维护的列表中查找合适空间
- 大对象可能直接进入老年代(受
-XX:PretenureSizeThreshold影响)
初始化零值与设置对象头(Zeroing & Object Header)
内存分配后,JVM将该内存区域初始化为零值(不包括对象头),保证实例字段即使未显式赋值也有默认值(如int → 0,Object → null)。同时设置对象头,包含:
立即学习“Java免费学习笔记(深入)”;
- Mark Word(存储哈希码、GC分代年龄、锁状态等)
- Klass Pointer(指向类元数据的指针,用于确定对象属于哪个类)
- 数组长度(仅数组对象有)
执行方法(构造器初始化)
最后,JVM调用对象的构造方法(即方法),按以下顺序执行:
- 调用父类构造器(隐式或显式
super()) - 执行实例变量显式初始化(如
private int x = 10;) - 执行实例代码块(
{ ... }) - 执行当前构造器方法体
注意:此时对象才真正“可用”;在构造器执行完毕前,若发生逃逸(如将this发布到其他线程),可能导致看到未完全初始化的对象状态。










