当前位置: 首页 > news >正文

JVM 类加载机制深度解析

目录

  • 第一章:类加载概述
  • 第二章:类加载过程
  • 第三章:类加载器体系
  • 第四章:双亲委派模型
  • 第五章:类加载时机
  • 第六章:自定义类加载器
  • 第七章:类加载实战演示

第一章:类加载概述

1.1 什么是类加载

类加载是 JVM 将字节码文件(.class)加载到内存中,并转换为可以被 JVM 执行的 Class 对象的过程。

1.2 类加载的作用

  1. 字节码验证:确保字节码文件符合 JVM 规范
  2. 内存分配:为类分配内存空间
  3. 符号引用解析:将符号引用转换为直接引用
  4. 初始化:执行类的初始化代码

1.3 类加载的时机

  • 创建类的实例
  • 访问类的静态变量
  • 调用类的静态方法
  • 使用反射访问类
  • 初始化子类时,父类会被加载
  • 虚拟机启动时,包含 main 方法的类会被加载

第二章:类加载过程

2.1 类加载的完整生命周期

类加载过程分为七个阶段:加载验证准备解析初始化使用卸载

// 类加载过程示例
public class ClassLoadingProcess {static {System.out.println("静态代码块执行 - 初始化阶段");}private static int staticVar = 10; // 准备阶段分配内存,初始化阶段赋值public static void main(String[] args) {System.out.println("main 方法执行");System.out.println("静态变量值: " + staticVar);}
}

2.2 加载(Loading)

目的:将字节码文件加载到内存中

过程

  1. 通过类的全限定名获取字节码文件
  2. 将字节码文件转换为方法区的运行时数据结构
  3. 在内存中生成一个代表该类的 Class 对象

代码示例

// 加载过程演示
public class LoadingDemo {public static void main(String[] args) {// 通过 Class.forName 显式加载类try {Class<?> clazz = Class.forName("java.lang.String");System.out.println("类加载成功: " + clazz.getName());System.out.println("类加载器: " + clazz.getClassLoader());} catch (ClassNotFoundException e) {e.printStackTrace();}}
}

2.3 验证(Verification)

目的:确保字节码文件的正确性和安全性

验证内容

  1. 文件格式验证:验证字节码文件格式
  2. 元数据验证:验证类的元数据信息
  3. 字节码验证:验证字节码指令
  4. 符号引用验证:验证符号引用的正确性

验证示例

// 验证过程演示
public class VerificationDemo {public static void main(String[] args) {// 尝试加载一个不存在的类try {Class<?> clazz = Class.forName("NonExistentClass");} catch (ClassNotFoundException e) {System.out.println("类不存在,验证失败: " + e.getMessage());}// 尝试加载一个格式错误的类try {Class<?> clazz = Class.forName("java.lang.String");// 验证类的元数据System.out.println("类名: " + clazz.getName());System.out.println("父类: " + clazz.getSuperclass());System.out.println("接口: " + Arrays.toString(clazz.getInterfaces()));} catch (Exception e) {System.out.println("验证失败: " + e.getMessage());}}
}

2.4 准备(Preparation)

目的:为类的静态变量分配内存并设置默认值

准备过程

  1. 为静态变量分配内存
  2. 设置默认值(0、false、null)
  3. 为常量分配内存并设置值

准备示例

// 准备阶段演示
public class PreparationDemo {// 准备阶段:分配内存,设置默认值 0private static int staticInt;// 准备阶段:分配内存,设置默认值 falseprivate static boolean staticBoolean;// 准备阶段:分配内存,设置默认值 nullprivate static String staticString;// 准备阶段:分配内存,设置值 100(常量)private static final int CONSTANT_INT = 100;static {// 初始化阶段:设置实际值staticInt = 10;staticBoolean = true;staticString = "Hello";}public static void main(String[] args) {System.out.println("静态变量值: " + staticInt);System.out.println("静态布尔值: " + staticBoolean);System.out.println("静态字符串: " + staticString);System.out.println("常量值: " + CONSTANT_INT);}
}

2.5 解析(Resolution)

目的:将符号引用转换为直接引用

解析内容

  1. 类或接口解析:将类或接口的符号引用转换为直接引用
  2. 字段解析:将字段的符号引用转换为直接引用
  3. 方法解析:将方法的符号引用转换为直接引用
  4. 接口方法解析:将接口方法的符号引用转换为直接引用

解析示例

// 解析过程演示
public class ResolutionDemo {public static void main(String[] args) {try {// 类解析Class<?> clazz = Class.forName("java.lang.String");System.out.println("类解析成功: " + clazz.getName());// 字段解析Field field = clazz.getDeclaredField("value");System.out.println("字段解析成功: " + field.getName());// 方法解析Method method = clazz.getMethod("length");System.out.println("方法解析成功: " + method.getName());// 接口方法解析Class<?> listClass = Class.forName("java.util.List");Method listMethod = listClass.getMethod("size");System.out.println("接口方法解析成功: " + listMethod.getName());} catch (Exception e) {System.out.println("解析失败: " + e.getMessage());}}
}

2.6 初始化(Initialization)

目的:执行类的初始化代码

初始化过程

  1. 执行静态代码块
  2. 为静态变量赋值
  3. 执行静态方法

初始化示例

// 初始化过程演示
public class InitializationDemo {// 静态变量private static int staticVar = 10;// 静态代码块static {System.out.println("静态代码块1执行");staticVar = 20;}// 静态代码块static {System.out.println("静态代码块2执行");staticVar = 30;}// 静态方法public static void staticMethod() {System.out.println("静态方法执行");}public static void main(String[] args) {System.out.println("main 方法执行");System.out.println("静态变量值: " + staticVar);staticMethod();}
}

2.7 使用(Using)

目的:类的正常使用阶段

使用过程

  1. 创建类的实例
  2. 调用实例方法
  3. 访问实例变量
  4. 调用静态方法
  5. 访问静态变量

使用示例

// 使用阶段演示
public class UsingDemo {private int instanceVar = 100;private static int staticVar = 200;public UsingDemo() {System.out.println("构造函数执行 - 使用阶段");}public void instanceMethod() {System.out.println("实例方法执行 - 使用阶段");System.out.println("实例变量值: " + instanceVar);}public static void staticMethod() {System.out.println("静态方法执行 - 使用阶段");System.out.println("静态变量值: " + staticVar);}public static void main(String[] args) {System.out.println("=== 使用阶段演示 ===");// 1. 调用静态方法staticMethod();// 2. 访问静态变量System.out.println("访问静态变量: " + staticVar);// 3. 创建实例UsingDemo demo = new UsingDemo();// 4. 调用实例方法demo.instanceMethod();// 5. 访问实例变量System.out.println("访问实例变量: " + demo.instanceVar);}
}

2.8 卸载(Unloading)

目的:从内存中移除不再使用的类

卸载条件

  1. 该类的所有实例都已经被回收
  2. 加载该类的 ClassLoader 已经被回收
  3. 该类的 Class 对象没有被任何地方引用

卸载过程

  1. 执行类的清理工作
  2. 释放类占用的内存
  3. 从方法区中移除类的信息

卸载示例

// 卸载过程演示
public class UnloadingDemo {static {System.out.println("UnloadingDemo 类加载 - 初始化阶段");}public UnloadingDemo() {System.out.println("UnloadingDemo 实例创建 - 使用阶段");}@Overrideprotected void finalize() throws Throwable {System.out.println("UnloadingDemo 实例被回收 - 卸载阶段");super.finalize();}public static void main(String[] args) throws InterruptedException {System.out.println("=== 卸载过程演示 ===");// 创建实例UnloadingDemo demo = new UnloadingDemo();// 使用实例System.out.println("使用实例: " + demo);// 释放引用demo = null;// 强制垃圾回收System.gc();// 等待垃圾回收完成Thread.sleep(1000);System.out.println("实例引用已释放,等待垃圾回收");}
}

第三章:类加载器体系

3.1 类加载器层次结构

Bootstrap ClassLoader (启动类加载器)↓
Extension ClassLoader (扩展类加载器)↓
Application ClassLoader (应用程序类加载器)↓
Custom ClassLoader (自定义类加载器)

3.2 启动类加载器(Bootstrap ClassLoader)

特点

  • 由 C++ 实现,是 JVM 的一部分
  • 负责加载核心类库(rt.jar、charsets.jar 等)
  • 是其他类加载器的父加载器
  • 无法被 Java 程序直接引用

代码示例

// 启动类加载器演示
public class BootstrapClassLoaderDemo {public static void main(String[] args) {// 获取核心类库的类加载器Class<?> stringClass = String.class;ClassLoader stringClassLoader = stringClass.getClassLoader();System.out.println("String 类的类加载器: " + stringClassLoader);System.out.println("String 类的类加载器是否为 null: " + (stringClassLoader == null));// 获取其他核心类的类加载器Class<?> objectClass = Object.class;ClassLoader objectClassLoader = objectClass.getClassLoader();System.out.println("Object 类的类加载器: " + objectClassLoader);System.out.println("Object 类的类加载器是否为 null: " + (objectClassLoader == null));}
}

3.3 扩展类加载器(Extension ClassLoader)

特点

  • 由 Java 实现
  • 负责加载扩展类库(jre/lib/ext 目录下的 jar 包)
  • 是应用程序类加载器的父加载器

代码示例

// 扩展类加载器演示
public class ExtensionClassLoaderDemo {public static void main(String[] args) {// 获取扩展类加载器ClassLoader extensionClassLoader = ClassLoader.getSystemClassLoader().getParent();System.out.println("扩展类加载器: " + extensionClassLoader);System.out.println("扩展类加载器类名: " + extensionClassLoader.getClass().getName());// 获取扩展类加载器的父加载器ClassLoader parent = extensionClassLoader.getParent();System.out.println("扩展类加载器的父加载器: " + parent);}
}

3.4 应用程序类加载器(Application ClassLoader)

特点

  • 由 Java 实现
  • 负责加载应用程序类路径(classpath)下的类
  • 是系统默认的类加载器

代码示例

// 应用程序类加载器演示
public class ApplicationClassLoaderDemo {public static void main(String[] args) {// 获取应用程序类加载器ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();System.out.println("应用程序类加载器: " + appClassLoader);System.out.println("应用程序类加载器类名: " + appClassLoader.getClass().getName());// 获取当前类的类加载器ClassLoader currentClassLoader = ApplicationClassLoaderDemo.class.getClassLoader();System.out.println("当前类的类加载器: " + currentClassLoader);// 验证是否为同一个类加载器System.out.println("是否为同一个类加载器: " + (appClassLoader == currentClassLoader));}
}

第四章:双亲委派模型

4.1 双亲委派模型原理

双亲委派模型是类加载器的工作机制,确保类的唯一性和安全性。

工作流程

  1. 当类加载器收到类加载请求时,首先委派给父加载器
  2. 如果父加载器无法加载,则由当前加载器加载
  3. 如果当前加载器也无法加载,则抛出 ClassNotFoundException

4.2 双亲委派模型实现

// 双亲委派模型演示
public class ParentDelegationDemo {public static void main(String[] args) {// 创建自定义类加载器CustomClassLoader customLoader = new CustomClassLoader();try {// 尝试加载 String 类Class<?> stringClass = customLoader.loadClass("java.lang.String");System.out.println("String 类加载成功: " + stringClass.getName());System.out.println("String 类的类加载器: " + stringClass.getClassLoader());// 尝试加载自定义类Class<?> customClass = customLoader.loadClass("ParentDelegationDemo");System.out.println("自定义类加载成功: " + customClass.getName());System.out.println("自定义类的类加载器: " + customClass.getClassLoader());} catch (ClassNotFoundException e) {System.out.println("类加载失败: " + e.getMessage());}}
}// 自定义类加载器
class CustomClassLoader extends ClassLoader {@Overrideprotected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {System.out.println("尝试加载类: " + name);// 首先检查类是否已经被加载Class<?> c = findLoadedClass(name);if (c != null) {System.out.println("类已加载: " + name);return c;}try {// 委派给父加载器if (getParent() != null) {System.out.println("委派给父加载器: " + name);c = getParent().loadClass(name);if (c != null) {System.out.println("父加载器加载成功: " + name);return c;}}} catch (ClassNotFoundException e) {System.out.println("父加载器无法加载: " + name);}// 当前加载器尝试加载System.out.println("当前加载器尝试加载: " + name);c = findClass(name);if (c != null) {System.out.println("当前加载器加载成功: " + name);if (resolve) {resolveClass(c);}return c;}throw new ClassNotFoundException(name);}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {// 这里可以实现自定义的类加载逻辑// 例如从网络、数据库等加载类throw new ClassNotFoundException(name);}
}

4.3 双亲委派模型的优势

  1. 类的唯一性:确保同一个类只被加载一次
  2. 安全性:防止核心类库被恶意替换
  3. 层次性:形成清晰的类加载器层次结构

4.4 双亲委派模型的破坏

破坏场景

  1. SPI 机制:ServiceLoader 使用线程上下文类加载器
  2. OSGi 框架:使用网状类加载器结构
  3. 热部署:需要重新加载类

破坏示例

// 双亲委派模型破坏示例
public class ParentDelegationBreakDemo {public static void main(String[] args) {// 使用线程上下文类加载器破坏双亲委派模型ClassLoader originalLoader = Thread.currentThread().getContextClassLoader();try {// 设置自定义类加载器为上下文类加载器CustomClassLoader customLoader = new CustomClassLoader();Thread.currentThread().setContextClassLoader(customLoader);// 使用 ServiceLoader 加载服务ServiceLoader<Object> serviceLoader = ServiceLoader.load(Object.class);System.out.println("ServiceLoader 使用上下文类加载器: " + Thread.currentThread().getContextClassLoader());} finally {// 恢复原始类加载器Thread.currentThread().setContextClassLoader(originalLoader);}}
}

第五章:类加载时机

5.1 类加载的触发条件

  1. 创建类的实例
  2. 访问类的静态变量
  3. 调用类的静态方法
  4. 使用反射访问类
  5. 初始化子类时,父类会被加载
  6. 虚拟机启动时,包含 main 方法的类会被加载

5.2 类加载时机演示

// 类加载时机演示
public class ClassLoadingTimingDemo {public static void main(String[] args) {System.out.println("=== 类加载时机演示 ===");// 1. 创建类的实例System.out.println("\n1. 创建类的实例");new InstanceClass();// 2. 访问类的静态变量System.out.println("\n2. 访问类的静态变量");System.out.println("静态变量值: " + StaticClass.staticVar);// 3. 调用类的静态方法System.out.println("\n3. 调用类的静态方法");StaticClass.staticMethod();// 4. 使用反射访问类System.out.println("\n4. 使用反射访问类");try {Class<?> clazz = Class.forName("ReflectionClass");System.out.println("反射加载类成功: " + clazz.getName());} catch (ClassNotFoundException e) {System.out.println("反射加载类失败: " + e.getMessage());}// 5. 初始化子类时,父类会被加载System.out.println("\n5. 初始化子类时,父类会被加载");new ChildClass();}
}// 实例类
class InstanceClass {static {System.out.println("InstanceClass 静态代码块执行");}public InstanceClass() {System.out.println("InstanceClass 构造函数执行");}
}// 静态类
class StaticClass {static {System.out.println("StaticClass 静态代码块执行");}public static int staticVar = 10;public static void staticMethod() {System.out.println("StaticClass 静态方法执行");}
}// 反射类
class ReflectionClass {static {System.out.println("ReflectionClass 静态代码块执行");}
}// 父类
class ParentClass {static {System.out.println("ParentClass 静态代码块执行");}
}// 子类
class ChildClass extends ParentClass {static {System.out.println("ChildClass 静态代码块执行");}
}

第六章:自定义类加载器

6.1 自定义类加载器实现

// 自定义类加载器实现
public class CustomClassLoader extends ClassLoader {private String classPath;public CustomClassLoader(String classPath) {this.classPath = classPath;}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {try {// 读取类文件byte[] classData = loadClassData(name);if (classData != null) {// 定义类return defineClass(name, classData, 0, classData.length);}} catch (IOException e) {e.printStackTrace();}throw new ClassNotFoundException(name);}private byte[] loadClassData(String name) throws IOException {String fileName = name.replace('.', '/') + ".class";String fullPath = classPath + "/" + fileName;try (FileInputStream fis = new FileInputStream(fullPath);ByteArrayOutputStream baos = new ByteArrayOutputStream()) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = fis.read(buffer)) != -1) {baos.write(buffer, 0, bytesRead);}return baos.toByteArray();}}
}

6.2 自定义类加载器使用示例

// 自定义类加载器使用示例
public class CustomClassLoaderDemo {public static void main(String[] args) {try {// 创建自定义类加载器CustomClassLoader customLoader = new CustomClassLoader("src");// 加载自定义类Class<?> clazz = customLoader.loadClass("CustomClass");System.out.println("类加载成功: " + clazz.getName());System.out.println("类加载器: " + clazz.getClassLoader());// 创建实例Object instance = clazz.newInstance();System.out.println("实例创建成功: " + instance);} catch (Exception e) {System.out.println("自定义类加载失败: " + e.getMessage());e.printStackTrace();}}
}// 自定义类
class CustomClass {static {System.out.println("CustomClass 静态代码块执行");}public CustomClass() {System.out.println("CustomClass 构造函数执行");}public void sayHello() {System.out.println("Hello from CustomClass!");}
}

第七章:类加载实战演示

7.1 完整的类加载演示

// 完整的类加载演示
public class ClassLoadingCompleteDemo {public static void main(String[] args) {System.out.println("=== JVM 类加载机制完整演示 ===\n");// 1. 类加载器层次结构演示demonstrateClassLoaderHierarchy();// 2. 双亲委派模型演示demonstrateParentDelegation();// 3. 类加载过程演示demonstrateClassLoadingProcess();// 4. 自定义类加载器演示demonstrateCustomClassLoader();// 5. 类加载时机演示demonstrateClassLoadingTiming();}/*** 演示类加载器层次结构*/private static void demonstrateClassLoaderHierarchy() {System.out.println("=== 类加载器层次结构演示 ===");// 获取当前类的类加载器ClassLoader currentLoader = ClassLoadingCompleteDemo.class.getClassLoader();System.out.println("当前类的类加载器: " + currentLoader);// 获取父加载器ClassLoader parent = currentLoader.getParent();System.out.println("父加载器: " + parent);// 获取祖父加载器ClassLoader grandparent = parent.getParent();System.out.println("祖父加载器: " + grandparent);// 获取核心类的类加载器ClassLoader stringLoader = String.class.getClassLoader();System.out.println("String 类的类加载器: " + stringLoader);System.out.println();}/*** 演示双亲委派模型*/private static void demonstrateParentDelegation() {System.out.println("=== 双亲委派模型演示 ===");try {// 尝试加载核心类Class<?> stringClass = Class.forName("java.lang.String");System.out.println("String 类加载成功: " + stringClass.getName());System.out.println("String 类的类加载器: " + stringClass.getClassLoader());// 尝试加载扩展类Class<?> listClass = Class.forName("java.util.List");System.out.println("List 接口加载成功: " + listClass.getName());System.out.println("List 接口的类加载器: " + listClass.getClassLoader());} catch (ClassNotFoundException e) {System.out.println("类加载失败: " + e.getMessage());}System.out.println();}/*** 演示类加载过程*/private static void demonstrateClassLoadingProcess() {System.out.println("=== 类加载过程演示 ===");try {// 加载类Class<?> clazz = Class.forName("ClassLoadingProcessDemo");System.out.println("类加载成功: " + clazz.getName());// 创建实例Object instance = clazz.newInstance();System.out.println("实例创建成功: " + instance);} catch (Exception e) {System.out.println("类加载过程演示失败: " + e.getMessage());}System.out.println();}/*** 演示自定义类加载器*/private static void demonstrateCustomClassLoader() {System.out.println("=== 自定义类加载器演示 ===");try {// 创建自定义类加载器CustomClassLoader customLoader = new CustomClassLoader("src");// 加载类Class<?> clazz = customLoader.loadClass("CustomClass");System.out.println("自定义类加载成功: " + clazz.getName());System.out.println("自定义类的类加载器: " + clazz.getClassLoader());} catch (Exception e) {System.out.println("自定义类加载器演示失败: " + e.getMessage());}System.out.println();}/*** 演示类加载时机*/private static void demonstrateClassLoadingTiming() {System.out.println("=== 类加载时机演示 ===");// 访问静态变量System.out.println("访问静态变量: " + TimingDemo.staticVar);// 调用静态方法TimingDemo.staticMethod();// 创建实例new TimingDemo();System.out.println();}
}// 类加载过程演示类
class ClassLoadingProcessDemo {static {System.out.println("ClassLoadingProcessDemo 静态代码块执行");}public ClassLoadingProcessDemo() {System.out.println("ClassLoadingProcessDemo 构造函数执行");}
}// 类加载时机演示类
class TimingDemo {static {System.out.println("TimingDemo 静态代码块执行");}public static int staticVar = 100;public static void staticMethod() {System.out.println("TimingDemo 静态方法执行");}public TimingDemo() {System.out.println("TimingDemo 构造函数执行");}
}

总结

JVM 类加载机制关键要点

  1. 类加载完整生命周期:加载 → 验证 → 准备 → 解析 → 初始化 → 使用 → 卸载
  2. 类加载器体系:启动类加载器 → 扩展类加载器 → 应用程序类加载器 → 自定义类加载器
  3. 双亲委派模型:确保类的唯一性和安全性
  4. 类加载时机:创建实例、访问静态成员、反射、初始化子类等
  5. 使用阶段:类的正常使用,包括实例创建、方法调用、变量访问等
  6. 卸载阶段:类的内存回收,需要满足三个条件才能被卸载
  7. 自定义类加载器:实现热部署、类隔离等功能

类加载机制的重要性

  • 安全性:防止核心类库被恶意替换
  • 唯一性:确保同一个类只被加载一次
  • 灵活性:支持自定义类加载逻辑
  • 性能:通过缓存和委派机制提高加载效率

通过深入理解 JVM 类加载机制,我们可以更好地理解 Java 程序的运行原理,也能在需要时实现自定义的类加载逻辑。

http://www.dtcms.com/a/463046.html

相关文章:

  • 【并发编程】详解volatile
  • 商务网站建设与维护实训报告网站建设的工作计划
  • 佛山电商网站制作那些网站是静态
  • 网络营销的发展趋势太原网站排名优化价格
  • 基于Qt框架开发的IP地址输入控件
  • Redis高可用与扩展性深度解析:主从复制、哨兵与集群
  • 深入理解手机快充技术:原理、协议与嵌入式实现
  • 小杰深度学习(seven)——卷积神经网络——池化
  • gSOAP: 一个C++构建Web服务和跨语言开发的利器
  • 网站简易后台计算机网站开发毕业设计论文开题报告
  • 广东网站建设公电子商务网站建设与管理课后题答案6
  • 个人网站不能有盈利性质wordpress 自定义分类 模板
  • 充值选建设银行打不开网站360免费wifi上不了网
  • 微信网站下载亚马逊雨林面积有多大
  • AI AgenticAI 教程:让AI成为学习与创作的智能伴侣
  • 跳舞游戏做的广告视频网站广告设计接单网站
  • 动画设计招聘信息太原seo管理
  • 再见用数字怎么表达?
  • DOM Comment
  • 举报非法网站要求做笔录淘宝权重查询入口
  • 自适应型网站建设网站设计学什么专业
  • 网站维护的基本概念营销网络是啥意思
  • 可以看禁止访问网站的浏览器做网站用是内网穿透好
  • 精选合肥网站建设网站建设所需要的材料
  • 集成mybatis
  • 做投诉网站赚钱吗平面图用什么软件做
  • 湛江网站建设方案报价wordpress 调用
  • 公司简介网站模板天津专业做网站
  • Unity中MonoBehavior类中的延迟函数Invoke详解(含案例)
  • app软件下载网站源码无锡企业网站