Java中类加载器的具体种类

你想系统了解Java中类加载器的具体种类,包括每种加载器的核心作用、加载范围和关键特点——这是理解Java类加载机制的核心,我会结合“作用+加载范围+代码验证”的方式,让你清晰掌握不同类加载器的区别。

Java的类加载器体系基于双亲委派模型(请求加载类时,先委托父加载器加载,父加载器加载不到才自己加载),主要分为内置类加载器(3种核心)和自定义类加载器,下面逐一详解:

一、内置类加载器(JVM自带,核心种类)

这是JVM默认提供的类加载器,按“优先级从高到低”分为3类:

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

  • 核心作用:加载JVM运行的核心类库,是整个类加载器体系的根。
  • 实现特点
    • 不是Java实现(由C/C++编写),属于JVM内核的一部分;
    • 没有对应的Java类(ClassLoader的子类),通过getClassLoader()获取时返回null
    • 最高优先级,没有父加载器。
  • 加载范围
    • JDK安装目录下jre/lib中的核心jar包(如rt.jarcharsets.jar,包含java.langjava.util等核心包);
    • 也可通过-Xbootclasspath参数手动指定加载路径。

2. 扩展类加载器(Extension ClassLoader)

  • 核心作用:加载JDK的扩展功能类库,补充核心类库之外的扩展功能。
  • 实现特点
    • 由Java实现(类名:sun.misc.Launcher$ExtClassLoader);
    • 父加载器是启动类加载器(逻辑上的父,因为启动类加载器不是Java类)。
  • 加载范围
    • JDK安装目录下jre/lib/ext中的扩展jar包;
    • 也可通过java.ext.dirs系统属性手动指定扩展类路径。

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

  • 别名:系统类加载器(System ClassLoader),是日常开发中最常用的加载器。
  • 核心作用:加载当前应用程序的类(我们自己写的代码、第三方依赖jar包)。
  • 实现特点
    • 由Java实现(类名:sun.misc.Launcher$AppClassLoader);
    • 父加载器是扩展类加载器
    • ClassLoader.getSystemClassLoader()的返回值,也是默认的类加载器(未指定时,所有用户类都由它加载)。
  • 加载范围
    • 应用的classpath路径下的所有类(包括src/main/java编译后的class文件、Maven引入的第三方jar包);
    • 可通过-cp-classpath参数修改classpath

代码验证:查看不同类的加载器

public class ClassLoaderDemo {
    public static void main(String[] args) {
        // 1. 核心类(如String):由启动类加载器加载(返回null)
        ClassLoader stringClassLoader = String.class.getClassLoader();
        System.out.println("String类的加载器:" + stringClassLoader); // null

        // 2. 扩展类(如com.sun.nio.zipfs.ZipFileSystem):由扩展类加载器加载
        ClassLoader extClassLoader = com.sun.nio.zipfs.ZipFileSystem.class.getClassLoader();
        System.out.println("扩展类的加载器:" + extClassLoader); // sun.misc.Launcher$ExtClassLoader@xxx

        // 3. 自定义类(当前类):由应用程序类加载器加载
        ClassLoader appClassLoader = ClassLoaderDemo.class.getClassLoader();
        System.out.println("自定义类的加载器:" + appClassLoader); // sun.misc.Launcher$AppClassLoader@xxx

        // 4. 获取系统类加载器(即应用程序类加载器)
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println("系统类加载器:" + systemClassLoader); // sun.misc.Launcher$AppClassLoader@xxx
    }
}

二、自定义类加载器(Custom ClassLoader)

  • 核心作用:满足特殊的类加载需求(内置加载器无法覆盖的场景)。
  • 实现方式
    • 继承java.lang.ClassLoader类;
    • 重写findClass()方法(推荐,不破坏双亲委派模型);
    • 若需自定义加载逻辑,也可重写loadClass()(不推荐,会破坏双亲委派)。
  • 应用场景
    1. 加载非classpath路径下的类(如从网络、数据库、加密文件中加载类);
    2. 实现类的热部署(如Tomcat的WebappClassLoader,为每个Web应用单独加载类);
    3. 对类进行加密/解密(加载前解密,防止类文件被反编译)。

简单自定义类加载器示例(加载指定路径的类)

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;

// 自定义类加载器
public class CustomClassLoader extends ClassLoader {
    // 自定义类加载路径
    private String classPath;

    public CustomClassLoader(String classPath) {
        this.classPath = classPath;
    }

    // 重写findClass,加载指定路径的类
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            // 将类名转为路径(如com.example.Test → com/example/Test.class)
            byte[] data = loadClassData(name);
            // 调用父类方法,将字节数组转为Class对象
            return defineClass(name, data, 0, data.length);
        } catch (Exception e) {
            throw new ClassNotFoundException(name);
        }
    }

    // 读取类文件的字节数组
    private byte[] loadClassData(String name) throws Exception {
        name = name.replace(".", "/");
        String path = classPath + "/" + name + ".class";
        try (InputStream is = new FileInputStream(path);
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            int b;
            while ((b = is.read()) != -1) {
                baos.write(b);
            }
            return baos.toByteArray();
        }
    }

    // 测试自定义类加载器
    public static void main(String[] args) throws Exception {
        // 自定义类加载路径(替换为你的class文件所在路径)
        CustomClassLoader loader = new CustomClassLoader("D:/custom_class");
        // 加载自定义类
        Class<?> clazz = loader.loadClass("com.example.Test");
        System.out.println("自定义类的加载器:" + clazz.getClassLoader()); // CustomClassLoader@xxx
    }
}

三、类加载器的核心规则:双亲委派模型

所有内置类加载器(除启动类)都遵循该模型,核心逻辑:

  1. 当类加载器收到加载请求时,先委托父加载器加载,自己不先处理;
  2. 父加载器若能加载,则返回Class对象;若加载不到(找不到类文件),子加载器才自己加载;
  3. 目的:保证核心类的唯一性和安全性(比如java.lang.String只能由启动类加载器加载,避免自定义String类篡改核心逻辑)。

总结

  1. 内置类加载器分3类:启动类加载器(C++实现,加载核心库)、扩展类加载器(加载扩展库)、应用程序类加载器(加载应用类,默认加载器);
  2. 自定义类加载器需继承ClassLoader,重写findClass(),用于特殊加载场景(如热部署、加密类加载);
  3. 类加载器遵循双亲委派模型,优先委托父加载器加载,保证核心类的安全和唯一性。
posted @ 2026-01-30 17:07  先弓  阅读(0)  评论(0)    收藏  举报