类加载器的分类

虚拟机自带的加载器

  • 启动类加载器(引导类加载器, Bootstrap classLoader)

    • 这个类加载使用 C/C++ 语言实现的,嵌套在 JVM 内部。
    • 它用来加载 Java 的核心库(JAVA_HOME/jre/lib/rt.jar、resources.jar、或 sun.boot.class.path 路径下的内容),用于提供 JVM 自身需要的类。
    • 并不继承自 java.lang.ClassLoader,没有父加载器。
    • 加载扩展类和应用程序类加载器,并指定为他们的父亲加载器。
    • 出于安全考虑, Bootstrap 启动类加载器只加载包名为:java、javax、sun 等开头的类。
  • 扩展类加载器(Extension ClassLoader)

    • Java 语言编写,由 sun.misc.Launcher$ExtClassLoader 实现。
    • 派生于 ClassLoader 类
    • 父类加载器为启动类加载器。
    • 从 java.ext.dirs 系统属性所指定的目录中加载类库,或从 JDK 的安装目录的 jre/lib/ext 子目录(扩展目录)下加载类库。如果用户创建的 JAR 放在此目录下,也会自动由扩展类加载器加载。
  • 应用程序类加载器(系统类加载器, AppClassLoader)

    • Java 语言编写,由 sun.misc.Launcher$AppClassLoader 实现。
    • 派生于 ClassLoader 类。
    • 父类加载器为扩展类加载器。
    • 它负责加载环境变量 classpath 或系统属性 java.class.path 指定路径下的类库。
    • 该类加载是程序中默认的类加载器,一般来说, Java 应用的类都是由他来完成加载。
    • 通过 ClassLoader#getSystemClassLoader() 方法可以获取到该类加载器。
  • 用户自定义类加载器

    • 在 Java 的日常应用程序开发中,类的加载几乎是由上述 3 中类加载器相互配合执行的,在必要的时候,我们还可以自定义类加载器,来定制类的加载方式。
    • 为什么要自定义类加载器?

      • 隔离加载类。
      • 修改类加载的方式。
      • 扩展加载源。
      • 防止源码泄露。
    • 用户自定义类加载器实现步骤:

      • 开发人员可以通过继承抽象类 java.lang.ClassLoader 类的方式,实现自己的类加载器,以满足一些特殊的需求。
      • 在 JDK1.2 之前,在自定义类加载器时,总会去继承 ClassLoader 类并重写 loadClass() 方法,从而实现自定义的类加载类,但是在 JDK1.2 之后已经不再建议用户去覆盖 loadClass() 方法,而是建议把自定义的类加载逻辑写在 findClass() 方法中。
      • 在编写自定义类加载器时,如果没有太过于复杂的需求,可以直接继承 URLClassLoader 类,这样就可以避免自己去编写 findClass() 方法及其获取字节码流的方式,使自定义类加载器编写更加简洁。

关于 ClassLoader

ClassLoader 类,它是一个抽象类,其后所有的类加载器都继承自 ClassLoader (不包括启动类加载器)。

方法名称描述
getParent()返回该类加载器的超类加载器
loadClass(String name)加载名称为 name 的类,返回结果为 java.lang.Class 类的实例
findClass(String name)查找名称为 name 的类,返回结果为 java.lang.Class 类的实例
findLoadedClass(String name)查找名称为 name 的已经被加载过的类,返回结果为 java.lang.Class 类的实例
defineClass(String name, byte[] b, int off, int len)把字节数组 b 中的内容转换为一个 Java 类,返回结果为 java.lang.Class 类的实例
resolveClass(Class<?> c)连接指定的一个 Java 类

sun.misc.Launcher 它是一个 Java 虚拟机的入口应用。

获取 ClassLoader 的途径

  • 方式一:获取当前类的 ClassLoader

    clazz.getClassLoader()

  • 方式二:获取当前线程上下文的 ClassLoader

    Thread.currentThread().getContextClassLoader()

  • 方式三:获取系统的 ClassLoader

    ClassLoader.getSystemClassLoader()

  • 方式四:获取调用者的 ClassLoader

    DriverManager.getCallerClassLoader()

public class ClassLoaderTest2 {
    public static void main(String[] args) {
        try {
            // 1.
            ClassLoader classLoader = Class.forName("java.lang.String").getClassLoader();
            System.out.println(classLoader);
            // 2.
            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
            System.out.println(contextClassLoader);

            // 3.
            ClassLoader parent = ClassLoader.getSystemClassLoader().getParent();
            System.out.println(parent);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
Last modification:April 21, 2020
如果觉得我的文章对你有用,请随意赞赏