Java 中 new 一个对象 的过程是从字节码解析到内存分配、初始化、引用返回的完整链路,涉及 JVM 类加载、内存管理、构造方法执行等核心机制。以下按「JVM 层面的核心步骤」+「代码层面的直观拆解」展开,兼顾底层原理和实际理解:
一、核心前提:类必须先加载(首次创建对象时)
如果该类从未被 JVM 加载过,执行 new 前会先触发类加载流程(加载→验证→准备→解析→初始化),确保类的元数据(如字段、方法、常量池)被加载到方法区(JDK 1.8+ 为元空间)。
- 加载:通过类的全限定名读取字节码文件(.class);
- 初始化:执行静态代码块(
<clinit>)、静态变量赋值(如static int a = 10); - 注意:类加载仅执行一次,后续创建该类对象时跳过此步骤。
二、new 对象的核心步骤(JVM 层面)
以 User user = new User("张三", 20); 为例,完整流程如下:
步骤 1:检查类加载状态 + 分配内存
JVM 先确认 User 类已加载,然后为新对象分配堆内存:
- 内存大小确定:根据类的元数据(字段类型、数量)计算对象所需内存(如对象头 + 实例字段 + 对齐填充);
- 内存分配方式:
- 「指针碰撞」:堆内存规整(Serial/ParNew 收集器),JVM 移动空闲指针,划分出对象所需内存;
- 「空闲列表」:堆内存碎片化(CMS 收集器),JVM 从空闲列表中找到足够大的内存块分配;
- 线程安全保障:
- 方案 1:CAS + 失败重试(保证分配原子性);
- 方案 2:TLAB(本地线程分配缓冲)—— 每个线程在堆中预留一小块内存,优先在 TLAB 分配,避免竞争(默认开启)。
步骤 2:内存初始化(零值填充)
分配完内存后,JVM 会将对象的实例字段初始化为对应类型的零值(不执行赋值语句,仅清空内存):
- 例如:
User的name字段(String 类型)被设为null,age字段(int 类型)被设为0,引用类型默认null,基本类型默认对应零值(boolean→false,long→0L 等); - 目的:保证对象字段在构造方法执行前,不会出现'未初始化的脏数据'。
步骤 3:设置对象头(Object Header)
在分配的内存中设置对象头信息,包含:
- Mark Word:存储对象的哈希值、GC 分代年龄、锁状态、偏向锁线程 ID 等;
- 类型指针:指向对象所属类的元数据(如
User.class),JVM 通过该指针确认对象的类型; - (数组对象额外)数组长度:若为数组对象,还会存储数组长度字段。
步骤 4:执行实例初始化方法(<init>)
这是「代码层面感知最明显」的步骤,JVM 调用对象的构造方法(<init> 是编译器生成的初始化方法,对应代码中的构造函数):
- 执行顺序:
- 先调用父类的
<init>方法(隐式super(),若未显式调用,编译器自动添加),递归直到Object类; - 执行实例变量的显式赋值(如
private String name = "默认名");
- 先调用父类的

