ClassLoader知识理解
发布日期:2021-05-14 13:44:42 浏览次数:16 分类:精选文章

本文共 2683 字,大约阅读时间需要 8 分钟。

ClassLoader基础概念与实现

Java作为一个由大量独立类文件组成的平台,与传统的编译语言如C或C++有着本质的区别。Java程序不是单一的可执行文件,而是由多个类文件组成,每一个文件对应一个Java类。这些类文件在程序运行时并不全部装入内存,而是根据程序的需要逐渐载入。而ClassLoader在JVM体系中扮演着核心角色,它是一个抽象类,专门负责在程序运行时装入类文件。ClassLoader有两个重要的实现类:ExtClassLoader和AppClassLoader。ExtClassLoader主要负责加载Java扩展API定义在目标目录/lib/ext中的类;而AppClassLoader则专门负责加载用户定义的CLASSPATH中的类。这两个ClassLoader都是Java程序自定义的。

ClassLoader的加载流程

JVM启动时会首先初始化bootstrap classloader(启动类加载器),这个类加载器负责装入Java核心API(java.lang包下的类)。随后,bootstrap classloader会加载ExtClassLoader和AppClassLoader。当程序运行时,ClassLoader会按照以下顺序加载类:首先是ExtClassLoader加载扩展API类;然后是AppClassLoader加载CLASSPATH目录中的类。这个过程遵循父类委托模式,确保了类的单例性和高效性。

protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// 检查是否已加载该类
Class c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 父类加载失败处理
}
if (c == null) {
long t1 = System.nanoTime();
c = findClass(name);
// 记录性能数据
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}

###父类委托模式的实现原因

  • 避免类重复加载:通过检查父ClassLoader是否已经装入该类,可以避免同一个ClassLoader多次尝试加载相同的类,减少内存占用和性能开销。

  • 提高安全性:父类委托模式确保了核心API类(如java.lang.String)只能由JVM中的bootstrap classloader加载,防止恶意类加载器替换核心API。

  • ClassLoader的重要方法解析

    • loadClass(String name, boolean resolve):ClassLoader的核心方法,负责根据类名请求对应的Class对象。
    • defineClass(byte[] classData, int offset, int count, ClassClassLoader loader):将原始字节流转化为Class对象的桥梁。
    • findSystemClass(String name):从本地文件系统找到对应classes文件,并将其加载到内存。
    • resolveClass(Class c):处理类的解析和初始化,完成类的生命周期。
    • findLoadedClass(String name):检查ClassLoader已加载的类缓存。
    • findClass(String name):从文件系统或其他来源找到类文件,并调用defineClass定义Class。
    • getSystemClassLoader():获取当前线程上下文的ClassLoader,支持类委托。
    • static Class forName(String name):通过ClassLoader加载指定类。

    ClassLoader的高级使用技巧

    在实际开发中,ClassLoader的强大功能可以用于定制类加载器,例如实现动态加载功能或创建自定义ClassLoader。以下是一些常用场景:

  • 自定义ClassLoader:创建一个继承自ClassLoader的类,覆盖findClass方法,实现自定义类的加载逻辑。
  • 远程类loading:加载网络或远程提供的类文件,支持动态更新。
  • 隔离性类loading:通过自定义ClassLoader实现类的封装与安全性。
  • 通过合理使用ClassLoader,可以显著提升Java程序的灵活性和安全性,同时优化类加载效率。作为开发者,深入理解ClassLoader的工作机制是构建高效且万无一失的应用必不可少。

    上一篇:Java的异常理解
    下一篇:Java的泛型

    发表评论

    最新留言

    哈哈,博客排版真的漂亮呢~
    [***.90.31.176]2025年04月09日 05时00分30秒