【JAVA】类加载器(ClassLoader)

JVM中的类加载器详解

类加载器(ClassLoader)是JVM中一个非常重要的组件,它负责将Java类文件加载到JVM的内存中,并对其进行验证、准备和解析。类加载器的主要任务是找到指定的类文件,并将其内容加载到内存中。

1. 类加载器的工作过程

类加载的过程主要分为三个步骤:

  • 加载(Loading): 查找并导入类的二进制数据。
  • 链接(Linking): 包括验证(Verification)、准备(Preparation)和解析(Resolution)三个阶段。
  • 初始化(Initialization): 执行类构造器 () 方法。

2. 类加载器的类型

JVM中有以下几种类型的类加载器:

  1. 启动类加载器(Bootstrap ClassLoader):
    • 负责加载核心类库,如rt.jar中的类。
    • 由C++实现,属于JVM的一部分,无法直接被Java代码访问。
  2. 扩展类加载器(Extension ClassLoader):
    • 负责加载扩展类库,如lib/ext目录中的类。
    • 使用Java编写,继承自ClassLoader。
  3. 应用程序类加载器(Application ClassLoader):
    • 负责加载应用程序的类路径下的类,如用户自定义类。
    • 默认的类加载器,继承自ClassLoader。

3. 类加载器的双亲委派模型

类加载器采用双亲委派模型(Parent Delegation Model),即当一个类加载器加载一个类时,它首先将请求委派给父类加载器。如果父类加载器无法完成这个加载任务,子类加载器才会尝试加载。这样可以确保Java核心类库优先被加载,避免用户自定义类覆盖JVM的核心类。

4. 自定义类加载器

在实际开发中,有时需要自定义类加载器以满足特定需求。自定义类加载器一般通过继承ClassLoader类,并重写findClass方法来实现。

示例代码:

public class CustomClassLoader extends ClassLoader { // 定义自定义类加载器,继承自ClassLoader
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classData = loadClassData(name); // 加载类文件的二进制数据
        if (classData == null) {
            throw new ClassNotFoundException(); // 如果类数据为空,则抛出类未找到异常
        } else {
            return defineClass(name, classData, 0, classData.length); // 将二进制数据转换为Class对象
        }
    }

    private byte[] loadClassData(String className) {
        String path = className.replace('.', '/') + ".class"; // 将类名转换为文件路径
        try {
            InputStream inputStream = new FileInputStream(path); // 打开类文件的输入流
            ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); // 用于存储类文件的字节数据
            int nextValue = 0;
            while ((nextValue = inputStream.read()) != -1) {
                byteStream.write(nextValue); // 读取类文件的数据并写入byteStream
            }
            return byteStream.toByteArray(); // 返回类文件的字节数据
        } catch (IOException e) {
            e.printStackTrace();
            return null; // 如果发生IO异常,则返回null
        }
    }

    public static void main(String[] args) {
        try {
            CustomClassLoader customClassLoader = new CustomClassLoader(); // 创建自定义类加载器实例
            Class<?> clazz = customClassLoader.loadClass("MyClass"); // 使用自定义类加载器加载类
            Object obj = clazz.newInstance(); // 实例化加载的类
            System.out.println("类加载成功:" + obj.getClass().getName()); // 打印类加载成功的信息
        } catch (Exception e) {
            e.printStackTrace(); // 捕获并打印异常
        }
    }
}

5. 源码解析

在JVM中,类加载器的核心类是java.lang.ClassLoader,它定义了类加载器的基本行为。下面简要解析ClassLoader的部分源码:

ClassLoader类的关键方法:

public abstract class ClassLoader {
    private final ClassLoader parent; // 父类加载器

    protected ClassLoader(ClassLoader parent) {
        this.parent = parent; // 构造函数初始化父类加载器
    }

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false); // 调用重载的loadClass方法
    }

    private Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            Class<?> c = findLoadedClass(name); // 检查类是否已经被加载过
            if (c == null) {
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false); // 使用父类加载器加载类
                    } else {
                        c = findBootstrapClassOrNull(name); // 尝试使用引导类加载器加载
                    }
                } catch (ClassNotFoundException e) {
                    c = findClass(name); // 如果父类加载器无法加载,调用findClass方法
                }
            }
            if (resolve) {
                resolveClass(c); // 链接类
            }
            return c; // 返回加载的类
        }
    }
}
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值