跳至主要內容

类加载器

荒流2020年10月11日大约 5 分钟约 1352 字

尽管在 Java 开发中无须过分关心类加载机制,但所有的编程人员都应该了解其工作机制。

1. 类加载器

类加载器负责将 .class 文件加载到内存中,并为之生成对应的 java.lang.Class 对象。

Java 类加载器除了根类加载器之外,其他类加载器都是使用 Java 语言编写的,所以程序员完全可以开发自己的类加载器。

在 Java 中,一个类用其全限定类名作为标识;但在 JVM 中,一个类用其全限定类名和其类加载器作为唯一标识。

当 JVM 启动时,会形成由三个类加载器组成的初始类加载器层次结构:

加载器说明作用
Bootstrap ClassLoader根类加载器负责加载 Java 的核心类
Extension ClassLoader扩展类加载器
System ClassLoader系统类加载器
import java.io.IOException;
import java.net.URL;
// Enumeration这种传统接口已被迭代器取代
// 虽然Enumeration 还未被遗弃,但在现代代码中已经被很少使用了。
import java.util.Enumeration;  

class ClassLoaderPropTest {
    public static void main(String[] args) throws IOException {
        // 获取系统类加载器
        ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
        System.out.println("系统类加载器:" + systemLoader);
        Enumeration<URL> eml = systemLoader.getResources("");
        while (eml.hasMoreElements()) {
            System.out.println(eml.nextElement());
        }
        ClassLoader extensionLoader = systemLoader.getParent();
        System.out.println("扩展类加载器:" + extensionLoader);
        System.out.println("扩展类加载器的加载路径:" + System.getProperty("java.ext.dirs"));
        System.out.println("扩展类加载器的parent:" + extensionLoader.getParent());
    }
    /*
     * 结果输出为:
     * 系统类加载器:jdk.internal.loader.ClassLoaders$AppClassLoader@5a2e4553
     * file:/C:/Users/Xuchuan/AppData/Roaming/Code/User/workspaceStorage/
     * 0619d618e4bae95f674d3adaa556f7c3/redhat.java/jdt_ws/tmp_693fe676/bin/
     * 扩展类加载器:jdk.internal.loader.ClassLoaders$PlatformClassLoader@5577140b
     * 扩展类加载器的加载路径:null
     * 扩展类加载器的parent:null
     */
}

2. 类加载机制

JVM 的类加载机制主要有如下三种:

  1. 全盘负责:当一个类加载器加载某个 Class 时,该 Class 所依赖的和引用的其他 Class 也将由该类加载器负责载入,除非显式使用另外一个类加载器载入;
  2. 父类委托:先让父类加载器试图加载该 Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类(类加载器之间的父子关系并不是类继承上的父子关系,而是类加载器实例之间的关系);
  3. 缓存机制:所有加载过的 Class 都会被缓存,当程序中需要使用某个 Class 时,类加载器先从缓存区中搜寻该 Class,只有当缓存区中不存在该 Class 对象时,系统才会读取该类对应的二进制数据,并将其转换成 Class 对象,存入缓存区中。这也是为什么修改了 Class 后必须重新启动 JVM,程序所做的修改才会生效的原因。

3. 自定义类加载器

ClassLoaderjava.lang 包下的一个抽象类,JVM 中除根类加载器之外的所有类加载器都是 ClassLoader 子类的实例,开发者可以通过扩展 ClassLoader 类来实现自定义的类加载器。

实际上,使用自定义的类加载器,可以实现如下常见功能:

  1. 执行代码前自动验证数字签名;
  2. 根据用户提供的密码解密代码,从而可以实现代码混淆器来避免反编译*.class文件;
  3. 根据用户需求来动态地加载类;
  4. 根据应用需求把其他数据以字节码的形式加载到应用中。

4. URLClassLoader类

Java 为 ClassLoader 抽象类提供了一个 URLClassLoader 实现类,该类也是系统加载器和扩展类加载器的父类。

URLClassLoader 的构造器:

对于上述的 URL 而言: