02_对象实例化流程(内存分配 初始化)
一、对象实例化概述
对象实例化是 Java 中创建对象的过程,通过new关键字触发,核心目标是在内存中为对象分配空间并完成初始化,最终得到一个可用的对象。整个流程可概括为:类加载检查→内存分配→初始化→返回对象引用,每个步骤都由 JVM 自动完成,确保对象的完整性和可用性。

二、对象实例化的核心流程
2.1 步骤 1:类加载检查
在执行new 类名(...)时,JVM 首先会检查该类是否已被加载到方法区:
- 若类未加载:JVM 会先执行类加载流程(加载、验证、准备、解析、初始化),将类的信息(如属性、方法、构造器定义)加载到方法区。
- 若类已加载:直接进入下一步。
作用:确保对象对应的类信息已存在,为后续内存分配和初始化提供依据。
示例:
// 执行new Person()时,JVM先检查Person类是否已加载
Person p = new Person();
2.2 步骤 2:内存分配
类加载检查通过后,JVM 会在堆内存中为新对象分配空间,空间大小由类的属性(成员变量)数量和类型决定(如int占 4 字节,Object引用占 8 字节等)。
内存分配的核心操作:
- 确定内存大小:根据类加载后确定的属性信息,计算出单个对象所需的总内存空间。
- 划分内存区域:从堆中划分出对应大小的连续空间给新对象,常用两种方式:
- 指针碰撞:若堆内存是连续的(无碎片),通过移动指针直接划分空间(如 Serial、ParNew 等收集器)。
- 空闲列表:若堆内存有碎片,JVM 通过维护 "空闲内存块列表",从中选择合适的块分配(如 CMS 收集器)。
2.3 步骤 3:初始化(核心阶段)
内存分配完成后,JVM 会对对象进行多阶段初始化,确保对象的属性有合理的初始值。初始化按以下顺序执行:
2.3.1 阶段 1:默认初始化(零值初始化)
JVM 自动为对象的所有属性赋默认值(与属性类型相关),确保对象在显式初始化前不会有垃圾值。
常见类型的默认值:
- 基本类型:int→0、boolean→false、double→0.0等。
- 引用类型:null(如String→null、Object→null)。
示例:
public class Person {
private int age; // 默认初始化:age=0
private String name; // 默认初始化:name=null
}
// 执行new Person()时,JVM先为age赋0,name赋null
2.3.2 阶段 2:显式初始化(代码定义时的初始化)
执行类中属性定义时显式指定的初始值(若有),覆盖默认初始化的值。
示例:
public class Person {
private int age = 18; // 显式初始化:覆盖默认值0→18
private String name = "未知"; // 显式初始化:覆盖默认值null→"未知"
}
// 显式初始化在默认初始化之后执行,因此age最终为18,name为"未知"
2.3.3 阶段 3:构造器初始化(执行构造器代码)
调用类的构造器,执行构造器中的代码,进一步初始化对象(如根据参数修改属性值),这是对象初始化的最后一步。
示例:
public class Person {
private int age = 18; // 显式初始化
private String name;
// 构造器
public Person(String name, int age) {
this.name = name; // 构造器初始化:为name赋值
this.age = age; // 构造器初始化:覆盖显式初始化的18
}
}
// 执行new Person("张三", 20)时:
// 1. 默认初始化:age=0,name=null
// 2. 显式初始化:age=18(覆盖默认值)
// 3. 构造器初始化:name="张三",age=20(覆盖显式初始化的值)
初始化顺序总结:默认初始化 → 显式初始化 → 构造器初始化(后续步骤的初始化会覆盖前序结果)。
2.4 步骤 4:返回对象引用
初始化完成后,JVM 会将堆中对象的内存地址(引用)返回给变量,此时变量指向堆中的对象,对象实例化完成,可通过变量操作对象。
示例:
// p接收对象的引用(堆中地址),p指向新创建的Person对象
Person p = new Person("张三", 20);
三、完整示例与流程解析
以Student类为例,完整展示对象实例化流程:
public class Student {
// 属性定义
private String school; // 默认初始化:null
private int grade = 1; // 显式初始化:1(覆盖默认值0)
private String name; // 默认初始化:null
// 构造器
public Student(String name, int grade) {
this.name = name; // 构造器初始化:name赋值
this.grade = grade; // 构造器初始化:覆盖显式初始化的1
}
public static void main(String[] args) {
// 实例化对象
Student s = new Student("李四", 3);
}
}
流程解析:
- 类加载检查:JVM 检查Student类是否加载,未加载则先加载。
- 内存分配:在堆中为Student对象分配空间(存储school、grade、name三个属性)。
- 初始化:
- 默认初始化:school=null,grade=0,name=null。
- 显式初始化:grade=1(覆盖默认值 0)。
- 构造器初始化:name="李四",grade=3(覆盖显式初始化的 1)。
- 返回引用:堆中对象的地址赋值给s,s指向该对象,实例化完成。
四、注意事项
- 初始化的不可跳过性:无论是否显式定义构造器,JVM 都会执行默认初始化和显式初始化,确保对象属性有合理初始值。
- 构造器的作用:构造器不负责分配内存(由 JVM 完成),仅用于最终的初始化(如根据参数定制对象)。
- 引用与对象的分离:变量存储的是对象的引用(地址),而非对象本身,对象始终存储在堆中。
- 实例化失败的情况:若类未找到(类加载失败)、内存不足(堆空间耗尽)或构造器执行异常,会导致实例化失败,抛出对应异常(如ClassNotFoundException、OutOfMemoryError)。
五、总结
Java 对象实例化是一个由 JVM 主导的有序过程,核心流程可归纳为:
- 类加载检查:确保类信息可用;
- 内存分配:在堆中为对象划分空间;
- 多阶段初始化:按 "默认初始化→显式初始化→构造器初始化" 的顺序完成属性赋值;
- 返回引用:将对象地址返回给变量,对象可用。
理解实例化流程有助于开发者清晰掌握对象的创建机制,避免因初始化顺序错误导致的逻辑问题(如在构造器中使用未初始化的属性)。

浙公网安备 33010602011771号