Skip to content

对象创建的过程是什么

在 Java 中,通过 new 关键字创建对象的过程主要包括以下步骤: 1. 类加载:加载类信息到方法区。 2. 内存分配:在堆中为对象分配内存空间。 3. 初始化零值:将对象内存清零(赋默认值)。 4. 设置对象头:写入对象元数据(如类指针、锁状态)。 5. 执行构造器:调用 <init> 方法,初始化实例字段。

1. 详细步骤分解

(1) 类加载

  • 触发条件
  • 首次使用类(如 new ClassName())。
  • 过程
  • JVM 检查类是否已加载。
  • 未加载则通过类加载器(ClassLoader)执行:
    1. 加载:读取 .class 文件到方法区。
    2. 链接
    3. 验证:检查字节码合法性。
    4. 准备:为静态变量分配内存,赋默认值。
    5. 解析:符号引用转为直接引用。
    6. 初始化:执行 <clinit> 方法(静态块、静态变量赋值)。
  • 结果
  • Class 对象就绪,存储在方法区。

(2) 内存分配

  • 位置
  • 堆内存(年轻代 Eden 区)。
  • 方式
  • 指针碰撞(Bump Pointer):
    • 假设堆内存连续,移动指针分配。
    • 适合串行、CMS 收集器。
  • 空闲列表(Free List):
    • 记录可用内存块,分配合适空间。
    • 适合并发收集器(如 G1)。
  • 线程安全
  • CAS + 失败重试:多线程竞争分配。
  • TLAB(Thread Local Allocation Buffer):线程私有缓冲区加速。

(3) 初始化零值

  • 过程
  • 分配的内存清零,字段赋默认值。
  • 默认值
  • int:0。
  • boolean:false。
  • 引用类型:null
  • 目的
  • 确保字段有定义状态,避免未初始化错误。

(4) 设置对象头

  • 对象头(Mark Word)
  • 包含:
    • 类指针:指向方法区的 Class 对象。
    • 锁状态:如无锁、偏向锁(用于 synchronized)。
    • 哈希码:调用 hashCode() 时生成。
    • GC 分代年龄:垃圾回收标记。
  • HotSpot 示例(64 位): 无锁: | hashCode | age | 0 |

(5) 执行构造器

  • 过程
  • 调用 <init> 方法(由编译器生成)。
  • 执行:
    1. 父类构造器:递归调用 super()
    2. 实例字段初始化:赋初始值(如 int x = 10)。
    3. 构造器代码:执行用户定义逻辑。
  • 字节码
new #2              // 创建对象 (ClassName)
dup
invokespecial #3    // 调用 <init>
astore_1            // 存储引用

示例

class Person {
    int age = 25; // 实例初始化
    String name;

    Person(String n) {
        this.name = n; // 构造器赋值
    }
}

Person p = new Person("Alice");
  • 过程
  • 加载 Person 类。
  • 分配内存(堆中)。
  • 零值:age = 0, name = null
  • 对象头:指向 PersonClass
  • <init>age = 25, name = "Alice"

2. JVM 视角

  • 字节码指令
  • new:分配内存。
  • dup:复制引用。
  • invokespecial:调用构造器。
  • 内存布局
  • 对象头:8-16 字节(32/64 位)。
  • 实例数据:字段值。
  • 对齐填充:补齐至 8 字节倍数。

图示

堆内存:
[ 对象头 | age (4字节) | name (引用) | 填充 ]

3. 注意事项

  • 异常
  • 类加载失败(如 ClassNotFoundException)。
  • 内存不足(OutOfMemoryError)。
  • 性能
  • TLAB 优化多线程分配。
  • JIT 编译消除冗余对象创建。

4. 延伸与面试角度

  • 与 static 初始化
  • <clinit>:类加载时静态初始化。
  • <init>:对象创建时实例初始化。
  • 单例模式
  • 控制创建过程(如 double-checked locking)。
  • 实际应用
  • Spring Bean:反射创建对象。
  • 面试点
  • 问“步骤”时,提五步流程。
  • 问“内存”时,提指针碰撞和对象头。

总结

Java 对象创建从类加载到构造器执行,涉及内存分配、零值初始化、对象头设置等步骤。JVM 通过优化(如 TLAB、锁升级)提升效率。面试时,可提字节码或画内存图,展示理解深度。