欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 艺术 > JVM 类加载机制

JVM 类加载机制

2025/2/21 2:59:09 来源:https://blog.csdn.net/weixin_37522117/article/details/145632347  浏览:    关键词:JVM 类加载机制

JVM 类加载机制详解

JVM(Java Virtual Machine,Java 虚拟机)中的类加载机制(Class Loading Mechanism)是指 JVM 在运行时动态加载 .class 文件,并将其转换为 JVM 识别的类对象(Class Object),以便执行。Java 的类加载采用按需加载(Lazy Loading)和双亲委派模型(Parent Delegation Model),确保类的安全性和避免重复加载。


1. 类加载的过程

Java 类的加载过程主要分为 五个阶段

  1. 加载(Loading)
  2. 连接(Linking)
    • 验证(Verification)
    • 准备(Preparation)
    • 解析(Resolution)
  3. 初始化(Initialization)
  4. 使用(Using)
  5. 卸载(Unloading)

(1)加载(Loading)

类加载阶段,JVM 通过类加载器(ClassLoader)从字节码文件.class)或其他来源(如网络、JAR包等)读取二进制数据,转换成方法区(Method Area)中的类对象

  • 加载的来源:

    • 本地 .class 文件
    • Jar 包
    • 网络(远程加载)
    • 动态代理生成的类
    • 其他自定义数据源
  • 主要任务:

    • 通过 类加载器 读取 .class 文件,生成二进制字节流
    • 将字节流解析为 JVM 内部数据结构,存放在方法区
    • 堆区(Heap)中生成该类的 Class 对象,用于管理该类的元数据。

示例:手动触发类加载

Class<?> clazz = Class.forName("com.example.MyClass"); // 反射触发类加载

(2)连接(Linking)

连接是把已经加载的类转换成可以运行的状态,包括三步

  1. 验证(Verification):确保 .class 文件格式正确,符合 JVM 规范,避免恶意字节码。
  2. 准备(Preparation):为类变量static 变量)分配内存,并初始化默认值(不执行赋值操作)。
  3. 解析(Resolution):把类中的符号引用转换为直接引用(指向方法区中具体的内存地址)。

示例:准备阶段

public class Example {static int x = 10; // x 的默认值在准备阶段是 0,初始化阶段才会变为 10
}

(3)初始化(Initialization)

类初始化是执行静态代码的过程:

  • 执行 static 变量的赋值静态代码块static {})。
  • 初始化的顺序 按类的继承关系 从父类到子类 依次进行。

示例:类初始化

class Parent {static int a = 1;static { System.out.println("Parent 初始化"); }
}
class Child extends Parent {static int b = 2;static { System.out.println("Child 初始化"); }
}
public class Test {public static void main(String[] args) {System.out.println(Child.b);}
}

输出:

Parent 初始化
Child 初始化
2

说明

  • Parent 先初始化,因为 Child 继承自 Parent
  • 只有 static 变量和 static 代码块才会在类初始化阶段执行。

(4)使用(Using)

类初始化完成后,就可以正常使用该类:

  • 创建对象
  • 调用静态方法
  • 访问静态变量

(5)卸载(Unloading)

类在以下情况下会被卸载:

  • 类的所有实例都被 GC
  • ClassLoader 被 GC
  • JVM 关闭

但是,JVM 不会卸载 Bootstrap ClassLoader 加载的类(即 rt.jar 内的核心类)。


2. Java 类加载器(ClassLoader)

类加载器负责将 .class 文件加载到 JVM。JVM 主要有三种类加载器:

类加载器作用负责加载的类
Bootstrap ClassLoader启动类加载器Java 核心类库(rt.jar
Extension ClassLoader扩展类加载器ext 目录下的 JAR
Application ClassLoader应用类加载器classpath 下的类

示例:查看类加载器

System.out.println(String.class.getClassLoader()); // null (Bootstrap 加载)
System.out.println(Test.class.getClassLoader());   // AppClassLoader

此外,Java 支持 自定义类加载器

示例:自定义 ClassLoader

class MyClassLoader extends ClassLoader {@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {byte[] bytes = loadClassData(name); // 自定义加载逻辑return defineClass(name, bytes, 0, bytes.length);}
}

3. 双亲委派机制(Parent Delegation Model)

工作原理

当一个 ClassLoader 需要加载类时,它不会直接加载,而是:

  1. 先委托给父类加载器。
  2. 父类加载失败(即找不到类)时,才会由子类加载器尝试加载。

作用

  • 避免重复加载:防止 Java 核心类(如 java.lang.String)被自定义类覆盖。
  • 提高安全性:防止恶意代码篡改 Java 标准库。

示例:双亲委派

public class Test {public static void main(String[] args) {System.out.println(Test.class.getClassLoader()); // AppClassLoaderSystem.out.println(String.class.getClassLoader()); // null (Bootstrap)}
}

4. 类的主动引用 & 被动引用

(1)主动引用(会触发类加载)

以下情况会触发类加载:

  • 创建对象new 关键字)
  • 访问静态变量
  • 调用静态方法
  • 反射
  • 子类初始化时,会先加载父类

示例:主动引用

class Parent {static { System.out.println("Parent 被加载"); }
}
public class Test {public static void main(String[] args) {Parent p = new Parent(); // 触发加载}
}

(2)被动引用(不会触发类加载)

  • 通过子类访问父类的静态变量
  • 访问 final 常量
  • Class.forName() 的 initialize=false 方式

示例:被动引用

class Parent {static { System.out.println("Parent 被加载"); }static int a = 10;
}
class Child extends Parent {}
public class Test {public static void main(String[] args) {System.out.println(Child.a); // 仅加载 Parent}
}

总结

  1. 类加载分为:加载、连接(验证、准备、解析)、初始化、使用、卸载。
  2. JVM 采用双亲委派机制,确保安全性和避免重复加载。
  3. 主动引用会触发类加载,被动引用不会

JVM 类加载机制是 Java 运行时的核心之一,理解它有助于优化内存管理和类加载行为。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词