📜  Java中的类加载器

📅  最后修改于: 2022-05-13 01:55:39.181000             🧑  作者: Mango

Java中的类加载器

Java类加载器Java运行时环境的一部分,它可以将Java类动态加载到Java虚拟机中。由于类加载器, Java运行时系统不需要了解文件和文件系统。

Java类不会一次全部加载到内存中,而是在应用程序需要时加载。此时, JRE调用Java ClassLoader ,这些 ClassLoader 将类动态加载到内存中。

Java中的类加载器类型

并非所有类都由单个 ClassLoader 加载。根据类的类型和类的路径,决定加载该特定类的 ClassLoader。要了解加载类的 ClassLoader,请使用getClassLoader()方法。所有类都根据它们的名称加载,如果找不到这些类中的任何一个,则返回NoClassDefFoundErrorClassNotFoundException

Java类加载器分为三种类型

  1. BootStrap ClassLoader:Bootstrap ClassLoader是一个机器代码,它在 JVM 调用它时启动操作。它不是一个Java类。它的工作是加载第一个纯Java ClassLoader。 Bootstrap ClassLoader 从rt.jar位置加载类。 Bootstrap ClassLoader 没有任何父 ClassLoader。它也被称为Primodial ClassLoader
  2. Extension ClassLoader: Extension ClassLoader 是 Bootstrap ClassLoader 的子类,从各自的 JDK Extension 库中加载核心Java类的扩展。它从jre/lib/ext目录或系统属性Java.ext.dirs指向的任何其他目录加载文件。
  3. 系统类加载器:应用程序类加载器也称为系统类加载器。它加载在环境变量CLASSPATH、-classpath 或 -cp 命令行选项中找到的应用程序类型类。 Application ClassLoader 是 Extension ClassLoader 的子类。

注意:ClassLoader 委托层次模型总是按照 Application ClassLoader->Extension ClassLoader->Bootstrap ClassLoader 的顺序运行。 Bootstrap ClassLoader 总是被赋予更高的优先级,其次是 Extension ClassLoader,然后是 Application ClassLoader。

Java ClassLoader 的功能原理

功能原则是Java类加载器工作的一组规则或特性。功能的三个原则,它们是:

  1. 委托模型: Java虚拟机和Java类加载器使用一种称为委托层次算法的算法将类加载到Java文件中。

    ClassLoader 基于委托模型给出的一组操作工作。他们是:

    • ClassLoader 始终遵循委托层次原则
    • 每当 JVM 遇到一个类时,它都会检查该类是否已经加载。
    • 如果该类已经加载到方法区域中,则 JVM 继续执行。
    • 如果该类不在方法区域中,则 JVM 要求Java ClassLoader Sub-System 加载该特定类,然后 ClassLoader 子系统将控制权移交给Application ClassLoader
    • 然后,Application ClassLoader 将请求委托给 Extension ClassLoader,而Extension ClassLoader又将请求委托给Bootstrap ClassLoader
    • Bootstrap ClassLoader 将在 Bootstrap 类路径(JDK/JRE/LIB)中搜索。如果类可用,则加载它,否则将请求委托给 Extension ClassLoader。
    • Extension ClassLoader 在 Extension Classpath(JDK/JRE/LIB/EXT) 中搜索类。如果类可用,则加载它,否则将请求委托给 Application ClassLoader。
    • Application ClassLoader 在 Application Classpath 中搜索类。如果该类可用,则加载它,如果不可用,则生成ClassNotFoundException异常。

  2. 可见性原则可见性原则指出,由父类加载器加载的类对子类加载器可见,但由子类加载器加载的类对父类加载器不可见。假设一个类 GEEKS.class 已被 Extension ClassLoader 加载,那么该类仅对 Extension ClassLoader 和 Application ClassLoader 可见,而对 Bootstrap ClassLoader 不可见。如果再次尝试使用 Bootstrap ClassLoader 加载该类,则会给出异常Java.lang.ClassNotFoundException
  3. 唯一性属性:唯一性属性确保类是唯一的并且没有类的重复。这也确保了父类加载器加载的类不会被子类加载器加载。如果父类加载器无法找到该类,那么只有当前实例会尝试自己这样做。

Java.lang.ClassLoader 的方法

在 JVM 请求类之后,需要执行几个步骤来加载类。类是根据委托模型加载的,但有一些重要的方法或函数在加载类中起着至关重要的作用。

  1. loadClass(String name, boolean resolve) :该方法用于加载JVM引用的类。它将类的名称作为参数。这是 loadClass(String, boolean) 类型。
  2. defineClass() :defineClass() 方法是最终方法,不能被覆盖。此方法用于将字节数组定义为类的实例。如果类无效,则抛出ClassFormatError
  3. findClass(String name) :此方法用于查找指定的类。此方法只查找但不加载类。
  4. findLoadedClass(String name) :该方法用于验证 JVM 引用的 Class 之前是否已加载。
  5. Class.forName(String name, boolean initialize, ClassLoader loader) :该方法用于加载类以及初始化类。此方法还提供了选择任何一个 ClassLoader 的选项。如果 ClassLoader 参数为 NULL,则使用 Bootstrap ClassLoader。

示例:在加载类之前执行以下代码:

protected synchronized Class
loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    Class c = findLoadedClass(name);
    try {
        if (c == NULL) {
            if (parent != NULL) {
                c = parent.loadClass(name, false);
            }
            else {
                c = findBootstrapClass0(name);
            }
        }
        catch (ClassNotFoundException e)
        {
            System.out.println(e);
        }
    }
}

注意:如果一个类已经被加载,它会返回它。否则,它将对新类的搜索委托给父类加载器。如果父类加载器没有找到该类, loadClass()调用方法findClass()来查找并加载该类。如果父ClassLoader没有找到该类, findClass()方法会在当前ClassLoader中搜索该类。