new 创建对象是jvm触发的有序内存操作:先加载初始化类,再在堆中分配内存(指针碰撞/空闲列表/tlab),接着零值初始化并设置对象头,最后执行构造方法;引用变量存储的是堆中对象地址。

创建引用类型对象时,new 不是简单“造一个对象”,而是触发 JVM 一系列确定、有序的内存操作。它本质是在堆中申请空间、赋予初始状态、完成定制初始化,并把地址交给你用。
类必须先加载,才能 new 出实例
执行 new Student() 前,JVM 会检查 Student 类是否已加载并初始化。若尚未加载,就启动类加载过程:读取 .class 文件 → 验证字节码 → 准备静态字段(赋默认值)→ 解析符号引用 → 执行 static 块和静态变量显式赋值。只有完成初始化,后续步骤才被允许。
堆内存分配:不止是“划一块地”
JVM 在堆中为对象分配内存,具体策略取决于 GC 算法和 JVM 参数:
- 指针碰撞:适用于内存规整场景(如 Serial、ParNew),JVM 移动一个“空闲指针”即可完成分配
- 空闲列表:适用于内存碎片化区域(如 CMS 的某些阶段),JVM 查找可用块并更新记录
- TLAB(线程本地缓冲区):为避免多线程竞争,每个线程在 Eden 区预分配私有小块,大多数小对象优先在此分配
对象初始化分两层:零值 + 构造逻辑
内存分配后,JVM 立即执行“零值初始化”:
- 所有实例字段设为默认值:
int→0,boolean→false,引用类型 →null - 同时设置对象头(Object Header),包含哈希码、GC 分代年龄、锁状态等元信息
紧接着调用构造方法——这才是你写的初始化逻辑真正生效的地方,它覆盖零值,赋予业务语义。
引用变量拿到的,只是一个地址
Student stu = new Student(); 中,stu 本身存于栈内存,它保存的是堆中那个对象的内存地址。这个地址是唯一标识,也是你后续调用 stu.getName() 或修改 stu.age 的依据。没有 new,就没有真实对象,也就没有可操作的地址。











