ClassLoader类加载过程

在 Java 中,类加载是 Java 虚拟机(JVM)将类的字节码文件从磁盘加载到内存中的过程。ClassLoader 是 Java 中负责类加载的类,它提供了加载类和资源的能力。

Java 类加载过程的基本步骤

Java 中的类加载过程通常遵循以下几个步骤:

  1. 加载(Loading)

    • ClassLoader 会从类路径(Classpath)或其他指定的地方查找字节码文件(.class 文件),并将其读取到内存中。
    • 在这个阶段,JVM 会根据全限定类名(包括包名)来查找相应的类文件。
    • ClassLoader 会将字节码文件转化为 Class 对象,表示加载的类。
  2. 验证(Verification)

    • 验证阶段是为了保证加载的类符合 JVM 规范,保证字节码的正确性和安全性。
    • 验证内容包括:
      • 确保字节码文件没有被篡改。
      • 确保类中的代码不违反 Java 语言规范。
      • 确保代码在执行时不会造成类加载器的安全漏洞。
  3. 准备(Preparation)

    • 这个阶段,JVM 会为类的静态变量分配内存,并设置初始值(默认值)。静态变量在类加载时就会被初始化。
    • 这个阶段只为类中的字段分配内存,并不会给它们赋值(除了 final 类型的静态变量,它们会被赋值)。
  4. 解析(Resolution)

    • 在这个阶段,JVM 会将类中的符号引用(如方法调用、字段访问等)转换为直接引用。
    • 例如,方法调用时,JVM 会把符号引用解析成真实内存地址。
  5. 初始化(Initialization)

    • 初始化阶段是在类的加载完成后执行的,主要是执行类中的静态初始化块(static 块)和静态变量的赋值操作。
    • 静态代码块在类加载完成后、类的实例化之前执行。
    • 如果类有父类,那么父类会先进行初始化。

ClassLoader 的工作机制

Java 使用 ClassLoader 来负责类的加载。JVM 默认提供了一个类加载器——系统类加载器System ClassLoader),但是你也可以自定义 ClassLoader 来加载类。Java 中有三种主要的类加载器:

  1. 启动类加载器(Bootstrap ClassLoader)

    • 启动类加载器是 JVM 的一部分,它负责加载 JRE/lib 目录下的核心类库(如 rt.jarresources.jar)。
    • 它是所有类加载器的父类加载器。
    • 启动类加载器不会直接继承 ClassLoader 类,而是由 JVM 提供实现。
  2. 扩展类加载器(Extension ClassLoader)

    • 扩展类加载器负责加载 JRE/lib/ext 目录下的类库。
    • 它继承自 ClassLoader,并加载 JDK 扩展库中的类。
  3. 系统类加载器(System ClassLoader)

    • 系统类加载器通常由 ClassLoader.getSystemClassLoader() 获取。它负责加载类路径(Classpath)下的类。
    • 该加载器负责加载用户自己编写的类文件及第三方库。

ClassLoader 的委托机制

Java 的类加载器采用了一种 委托模型,即当一个类加载器加载类时,它会先委托给父加载器加载。如果父加载器无法加载类,那么子加载器才会尝试加载该类。

  • 父类委托机制
    • 类加载器会尝试从其父加载器开始加载类,直到 Bootstrap ClassLoader
    • 这种机制可以避免类的重复加载。例如,System ClassLoader 会先请求 Extension ClassLoader 加载,如果它加载失败,再由 System ClassLoader 加载。
    • 这样做的好处是确保核心类库(如 rt.jar)不会被重复加载,也可以避免用户类与核心类库之间的冲突。

自定义 ClassLoader

Java 提供了 ClassLoader 类及其子类(如 URLClassLoader)来实现类加载器的自定义。通过继承 ClassLoader 类,可以实现自己的类加载逻辑。

例如,若你需要从网络中加载类,可以实现一个自定义的 ClassLoader

public class MyClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classData = loadClassData(name); // 加载类字节码
        return defineClass(name, classData, 0, classData.length);
    }

    private byte[] loadClassData(String name) {
        // 自定义加载字节码的逻辑(比如从文件、网络等地方加载)
        return new byte[0];
    }
}

类加载的顺序

  1. Bootstrap ClassLoader -> Extension ClassLoader -> System ClassLoader(根据类的来源逐级加载)。

类加载的生命周期

  1. 类的加载是延迟的,即 懒加载。当首次访问某个类时,类才会被加载。
  2. 类加载的过程是只发生一次的,一旦类被加载,它就会被缓存,并且在整个应用生命周期内保持在内存中,直到 JVM 退出。

类加载器的父子关系

  • 类加载器之间存在父子关系,每个类加载器都有一个父类加载器。即使是自定义的类加载器,它也会遵循父子关系。
  • ClassLoader 类提供了 getParent() 方法,可以查看当前类加载器的父类加载器。

总结

  1. 类加载过程包括加载、验证、准备、解析和初始化阶段。
  2. Java 的类加载器体系通过 委托机制 确保类的唯一性和安全性。
  3. Java 提供了三个主要的类加载器:Bootstrap ClassLoaderExtension ClassLoaderSystem ClassLoader,以及自定义类加载器的扩展。
  4. 类加载是懒加载的,且只会加载一次,之后会缓存类的字节码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值