Java 中的类加载器(Class Loaders in Java)

1. 介绍

类加载器(Class Loader)是一个负责加载类的对象。此外,类加载器在运行时动态地将 Java 类加载到 JVM(Java 虚拟机)中。它们也是 JRE(Java 运行时环境)的一部分。因此,多亏了类加载器,JVM 在运行 Java 程序时无需了解底层文件或文件系统。

此外,JVM 并不是一次性将所有这些 Java 类加载到内存中,而是当应用程序需要时才会加载。这就是类加载器发挥作用的地方。它们负责将类加载到内存中。

在本教程中,我们将讨论不同类型的内置类加载器及其工作原理。然后我们将介绍我们自定义的实现。

2. 类加载器(Class Loader)的功能是什么?

类加载器主要有两个功能:

  • 加载类 - 不同的内置和自定义类加载器会加载类。我们可以通过扩展 java.lang.ClassLoader 抽象类来创建类加载器实现

  • 定位资源 - 资源是一些数据,例如 .class 文件、配置信息或图像。我们通常将资源与应用程序或库打包在一起,以便于定位

一开始,类加载器不会为数组类创建对象。相反,Java 运行时会根据需要自动创建它们。因此,当我们使用 Class#getClassLoader() 来查找数组类的类加载器时,它会返回其元素类型的类加载器。相应地,如果元素类型是原始数据类型,则数组类没有类加载器。

3. 内置类加载器(Built-in Class Loaders)的类型

Java 运行时支持三种内置类加载器:

  • 引导类加载器(Bootstrap class loader ) - 虚拟机的内置类加载器,表示为 null

  • 平台类加载器(Platform class loader) - 加载平台类,包括 Java SE 平台 API、其实现类和特定于 JDK 的运行时类。平台类加载器是系统类加载器的父类加载器

  • 系统类加载器(System class loader) - 也称为 应用程序类加载器,加载应用程序类路径、模块路径和特定于 JDK 的工具上的类

3.1. 示例

让我们首先了解如何使用不同的类加载器加载不同的类:

public void printClassLoaders() throws ClassNotFoundException {

    System.out.println("平台类加载器:"
      + ClassLoader.getPlatformClassLoader());

    System.out.println("系统类加载器:"
      + ClassLoader.getSystemClassLoader());

    System.out.println("此类的类加载器:"
      + PrintClassLoader.class.getClassLoader());

    System.out.println("DriverManager 的类加载器:"
      + DriverManager.class.getClassLoader());

    System.out.println("ArrayList 的类加载器:"
      + ArrayList.class.getClassLoader());
}

执行上述方法时,输出为:

平台类加载器:jdk.internal.loader.ClassLoaders$PlatformClassLoader@5674cd4d
系统类加载器:jdk.internal.loader.ClassLoaders$AppClassLoader@33909752
此类的类加载器:jdk.internal.loader.ClassLoaders$AppClassLoader@33909752
DriverManager 的类加载器:jdk.internal.loader.ClassLoaders$PlatformClassLoader@5674cd4d
ArrayList 的类加载器:null

正如我们所见,这里有三种不同的类加载器:引导类加载器(显示为 null)、平台类加载器和系统类加载器。

系统类加载器加载包含示例方法的类。请记住,系统类加载器加载我们类路径中的文件

接下来,平台类加载器加载 DriverManager 类。

最后,引导类加载器加载 ArrayList 类。引导类加载器或原始类加载器是所有其他类加载器的父类加载器;然而,它本身没有父类加载器

然而,我们可以看到对于 ArrayList,输出中显示为 null这是因为引导类加载器是用本机代码而不是 Java 编写的,因此不会作为 Java 类显示。因此,引导类加载器的行为在不同的 JVM 中会有所不同。

现在,让我们更详细地讨论每种类加载器。

3.2. 引导类加载器(Bootstrap Class Loader)

java.lang.ClassLoader 的实例加载 Java 类。然而,类加载器本身也是类。因此,问题来了,谁来加载 java.lang.ClassLoader 本身呢?这就是引导类加载器或原始类加载器发挥作用的地方。它主要负责加载 JDK 内部类,通常是位于 $JAVA_HOME/jre/lib 目录中的 rt.jar 和其他核心库。此外,引导类加载器作为所有其他 ClassLoader 实例的父类加载器

正如前面示例中指出的,引导类加载器是核心 JVM 的一部分,是用本机代码编写的。不同平台可能对这个特定的类加载器有不同的实现。

3.3. 平台类加载器(Platform Class Loader)

平台类加载器是引导类加载器的子类加载器,负责加载标准核心 Java 类,以便它们对平台上运行的所有应用程序都可用。

3.4. 系统类加载器(System Class Loader)

另一方面,系统类加载器或应用程序类加载器负责将所有应用程序级别的类加载到 JVM 中。它加载类路径环境变量、-classpath 或 -cp 命令行选项中找到的文件。它也是平台类加载器的子类加载器。

4. 类加载器是如何工作的?

类加载器是 Java 运行时环境的一部分。当 JVM 请求一个类时,类加载器会尝试查找该类,并使用全限定类名将类定义加载到运行时中。java.lang.ClassLoader.loadClass(String name, boolean resolve) 方法负责使用其二进制名称将类定义加载到运行时中。这个方法是一个重载方法;它有一个参数不同的变体 java.lang.ClassLoader.loadClass(String name)。它执行有序搜索:

  1. 它调用 findLoadedClass(String name) 来检查类是否已经被加载。如果加载器已经加载了具有给定二进制名称的类,则返回该类;否则,返回 null

  2. 它在父类加载器上调用 loadClass(String) 方法。此外,如果父类加载器为 null,则使用虚拟机的内置类加载器。

  3. 它调用 findClass(String) 方法来查找类。

作为有序搜索的结果,如果未找到类,并且我们已将 resolve 标志设置为 true,则在结果二进制 Class 对象上调用 resolveClass(Class) 方法。

作为有序搜索的结果,如果未找到类,则抛出 java.lang.ClassNotFoundException

现在,让我们来考察类加载器的三个重要特性。

4.1. 委派模型(Delegation Model)

委派模型(Delegation Model)意味着 ClassLoader 类在尝试自行查找类或资源之前,将其查找类或资源的请求委派给其父类加载器。委派模型默认是分层的。ClassLoader 类支持类的并发加载;因此,它是可并行的。类加载器实现可以在初始化时注册自己,以实现并行。

类加载器遵循委派模型,其中 当被请求查找类或资源时,ClassLoader 实例会将类或资源的查找请求委派给父类加载器

假设我们有一个将应用程序类加载到 JVM 中的请求。系统类加载器首先将其父类加载器(平台类加载器)委派去加载该类,而平台类加载器又将其委派给引导类加载器。

只有当引导类加载器和平台类加载器都未能加载该类时,系统类加载器才会尝试自行加载该类。

4.2. 唯一的类(Unique Classes)

由于委派模型,确保唯一的类变得很容易,因为我们总是试图向上委派。

如果父类加载器无法找到该类,当前实例才会尝试自行查找。

4.3. 可见性(Visibility)

此外,子类加载器对父类加载器加载的类是可见的

例如,系统类加载器加载的类可以查看平台类加载器和引导类加载器加载的类,但反之则不行。

为了说明这一点,如果类 A 是由应用程序类加载器加载的,而类 B 是由平台类加载器加载的,那么对于应用程序类加载器加载的其他类来说,类 A 和 B 都是可见的。

然而,对于平台类加载器加载的其他类来说,只有类 B 是可见的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值