Java中类加载的过程是怎么样的?

1 个回答

  • ketty
    不必太张扬,是花自然香。
    ### **Java 中类的加载过程** Java 类的加载过程分为 **加载(Loading)**、**链接(Linking)** 和 **初始化(Initialization)** 三个主要阶段。其中,链接阶段又细分为验证、准备和解析。 ### **1. 加载阶段(Loading)** **目的**:将类的 `.class` 文件加载到 JVM 中。 - **主要任务**: 1. 根据类的全限定名获取定义该类的二进制字节流(来源包括文件系统、网络、运行时生成等)。 2. 将字节流对应的静态存储结构转化为方法区的运行时数据结构。 3. 在内存中创建一个 `java.lang.Class` 对象,作为类的访问入口。 ### **2. 链接阶段(Linking)** 链接是类加载的重要步骤,分为以下三个子阶段: #### **2.1 验证(Verification)** **目的**:确保类的字节码文件符合 JVM 的规范,防止非法代码运行。 - 验证内容: 1. **文件格式**:如 `.class` 文件的魔数和版本号。 2. **元数据验证**:确保类、字段、方法的描述符合法。 3. **字节码验证**:确保指令流合法,操作数栈不会溢出或下溢。 4. **二进制兼容性**:检查类的父类和接口是否存在。 #### **2.2 准备(Preparation)** **目的**:为类的静态变量分配内存并设置默认值。 - 特点: - 内存分配在方法区。 - 初始化值为默认值(如 `int` 为 `0`,`boolean` 为 `false`,对象为 `null`)。 - 静态变量的显式初始化(如赋值语句)不在此阶段完成。 #### **2.3 解析(Resolution)** **目的**:将常量池中的符号引用转为直接引用。 - **符号引用**:逻辑名称或标识符,如类名、方法名、字段名。 - **直接引用**:运行时具体的内存地址或偏移量。 - 解析内容包括: 1. 类或接口。 2. 字段。 3. 方法(类方法和接口方法)。 4. 方法类型和句柄。 ### **3. 初始化阶段(Initialization)** **目的**:执行类的 `<clinit>` 方法(类构造器方法),完成静态变量的显式初始化和静态代码块的执行。 #### **触发条件**: 1. **主动使用类时触发**: - 执行 `new` 操作(实例化类)。 - 访问静态字段(非 `final` 修饰的)。 - 调用静态方法。 2. **反射调用类时触发**: - 使用 `java.lang.reflect` 包方法调用类。 3. **父类初始化时触发**: - 如果子类被初始化,父类必须先初始化。 4. **主类初始化**: - JVM 启动时指定的主类会首先初始化。 5. **动态语言支持**: - 如果 `MethodHandle` 最终指向静态方法或字段,也会触发初始化。 ### **扩展:符号引用和直接引用** - **符号引用**: - 编译期间生成,与具体内存地址无关。 - 如类名、字段名、方法名。 - **直接引用**: - 运行时生成,直接指向内存地址。 - 如字段的内存地址、方法的实际调用地址。 **解析过程**: 在链接阶段的解析子阶段,JVM 将符号引用转为直接引用,用于高效访问。 ### **总结** Java 类的加载过程分为: 1. **加载阶段**:获取二进制字节流并生成 `Class` 对象。 2. **链接阶段**: - 验证:确保类的安全性和规范性。 - 准备:为静态变量分配内存并赋默认值。 - 解析:将符号引用转为直接引用。 3. **初始化阶段**:执行类的静态初始化代码。 这个过程确保类从加载到使用的正确性和高效性。
    发布于 2024-12-31 04:09 •IP属地 云南
    举报
    评论
    收藏