Java创建对象完整流程详解

Java创建对象完整流程详解

自己的简单描述

java需要创建一个对象的大致过程:编写A类java文件 ——》编译成A类.class文件——》jvm读取A类.class文件——》类加载器加载生成对应的唯一的A类Class对象 ——》通过A类Class对象生成普通A类实例对象

更准确的创建对象流程:

1. 编写源代码 (编写 A.java 文件)

public class A {
    private String name;
    
    public A(String name) {
        this.name = name;
    }
}

2. 编译阶段 (javac 编译)

javac A.java → 生成 A.class 文件

3. 类加载阶段 (JVM 执行时)

deepseek_mermaid_20251202_f1c832

类加载详细过程:

  • 加载:将 .class 文件二进制数据读入内存
  • 验证:验证字节码的合法性
  • 准备:为静态变量分配内存并设置默认值
  • 解析:将符号引用转换为直接引用
  • 初始化:执行静态代码块和静态变量赋值

4. 获取 Class 对象

// 方式1:通过类名.class
Class<A> clazz1 = A.class;

// 方式2:通过对象.getClass()
A obj = new A("test");
Class<? extends A> clazz2 = obj.getClass();

// 方式3:通过Class.forName()
Class<?> clazz3 = Class.forName("com.example.A");

5. 创建实例对象

// 方式1:使用 new 关键字(最常用)
A obj1 = new A("张三");
 // 底层其实等同于:
// 1. JVM 查找 String 类的 Class 对象。没找到时,触发类加载,生成Class对象。
// 2. 通过 Class 对象获取对象大小、布局等信息
// 3. 在堆中分配内存
// 4. 调用构造函数初始化

// 方式2:使用 Class.newInstance()(已过时)
A obj2 = A.class.newInstance();  // 要求有无参构造器

// 方式3:使用 Constructor.newInstance()
Constructor<A> constructor = A.class.getConstructor(String.class);
A obj3 = constructor.newInstance("李四");

// 方式4:使用 clone()
A obj4 = obj1.clone();  // 需要实现 Cloneable 接口

// 方式5:使用反序列化
// ObjectInputStream.readObject()

Class 对象在对象创建中的关键作用

// 从虚拟机角度看 new A() 的过程:
public class JVMPerspective {
    public static void main(String[] args) {
        // 当我们写 new A() 时,虚拟机实际做了:
        
        // 1. 查找 A 类的 Class 对象(如果未加载则先加载)
        Class<?> aClass = findClassInMethodArea("A");
        
        // 2. 根据 Class 对象信息分配内存
        //    - 对象头大小(mark word + class pointer)
        //    - 实例数据大小(所有实例字段)
        //    - 对齐填充
        long objectSize = calculateObjectSize(aClass);
        
        // 3. 在堆中分配内存
        Object rawMemory = allocateInHeap(objectSize);
        
        // 4. 初始化对象头(设置 mark word,指向 Class 对象)
        initObjectHeader(rawMemory, aClass);
        
        // 5. 初始化实例字段为零值
        initInstanceFieldsToZero(rawMemory, aClass);
        
        // 6. 调用构造函数 <init>
        invokeConstructor(rawMemory, aClass);
        
        // 7. 返回对象引用给栈帧
        return rawMemory;
    }
}

字节码层面看

// Java 源代码
A obj = new A("张三");

// 对应的字节码
0: new           #2      // class A
3: dup
4: ldc           #3      // String "张三"
6: invokespecial #4      // Method A."<init>":(Ljava/lang/String;)V
9: astore_1

字节码解析:

  • new 指令:在堆中分配内存(根据 Class 对象中的元数据(对象大小、字段布局等)分配内存),但对象还未初始化(状态为"未完成初始化")
  • dup 指令:复制引用(为构造函数调用准备)
  • invokespecial 指令:调用构造函数,完成对象初始化

总结:

  1. 所有对象创建都依赖 Class 对象,无论使用哪种方式(new、反射、克隆等)
  2. new 关键字的底层原理
    • JVM 通过类名找到对应的 Class 对象
    • 根据 Class 对象中的元数据(对象大小、字段布局等)分配内存
    • 初始化对象头,设置 klass pointer 指向该 Class 对象
    • 执行构造函数
  3. Class 对象是运行时类型信息的载体
    • 没有 Class 对象,JVM 不知道如何创建对象
    • 没有 Class 对象,对象不知道自己是什么类型
    • 没有 Class 对象,无法进行方法调用(动态绑定)

关键点总结:

  1. Class 对象的唯一性:每个类在 JVM 中只有一个 Class 对象(由类加载器+类全限定名决定)
  2. 类加载时机:不一定在程序启动时,而是在第一次使用时(懒加载)
  3. 对象创建流程
    • 分配内存空间
    • 初始化零值(默认值)
    • 设置对象头(hashcode、GC分代年龄等)
    • 执行 <init> 方法(构造函数)

示例代码验证:

public class TestClassLoad {
    static {
        System.out.println("TestClassLoad 静态代码块执行");
    }
    
    public static void main(String[] args) throws Exception {
        System.out.println("=== 第一次创建对象 ===");
        TestClassLoad obj1 = new TestClassLoad();
        
        System.out.println("=== 获取Class对象 ===");
        Class<?> clazz = Class.forName("TestClassLoad");
        
        System.out.println("=== 通过反射创建对象 ===");
        TestClassLoad obj2 = (TestClassLoad) clazz.newInstance();
    }
}

这就是 Java 中从编写类到创建对象的完整过程,理解了这些有助于深入理解 Java 的运行时机制。

posted @ 2025-12-02 20:49  deyang  阅读(32)  评论(0)    收藏  举报