likes
comments
collection
share

类加载器 理论整理

作者站长头像
站长
· 阅读数 37

类加载器

类加载

类加载方式:

  • 隐式加载:不直接在代码中调用 ClassLoader 的方法加载类对象

    • 创建类对象、使用类的静态域、创建子类对象、使用子类的静态域
    • 在 JVM 启动时,通过三大类加载器加载 class
  • 显式加载:

    • ClassLoader.loadClass(className):只加载和连接,不会进行初始化
    • Class.forName(String name, boolean initialize, ClassLoader loader):使用 loader 进行加载和连接,根据参数 initialize 决定是否初始化

类的唯一性:

  • 在 JVM 中表示两个 class 对象判断为同一个类存在的两个必要条件:

    • 类的完整类名必须一致,包括包名
    • 加载这个类的 ClassLoader(指 ClassLoader 实例对象)必须相同
  • 这里的相等,包括类的 Class 对象的 equals() 方法、isAssignableFrom() 方法、isInstance() 方法的返回结果为 true,也包括使用 instanceof 关键字做对象所属关系判定结果为 true

命名空间:

  • 每个类加载器都有自己的命名空间,命名空间由该加载器及所有的父加载器所加载的类组成

  • 在同一命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类

基本特征:

  • 可见性,子类加载器可以访问父加载器加载的类型,但是反过来是不允许的

  • 单一性,由于父加载器的类型对于子加载器是可见的,所以父加载器中加载过的类型,不会在子加载器中重复加载


加载器

类加载器是 Java 的核心组件,用于加载字节码到 JVM 内存,得到 Class 类的对象

从 Java 虚拟机规范来讲,只存在以下两种不同的类加载器:

  • 启动类加载器(Bootstrap ClassLoader):使用 C++ 实现,是虚拟机自身的一部分

  • 自定义类加载器(User-Defined ClassLoader):Java 虚拟机规范将所有派生于抽象类 ClassLoader 的类加载器都划分为自定义类加载器,使用 Java 语言实现,独立于虚拟机

从 Java 开发人员的角度看:

  • Bootstrap ClassLoader(最顶层的类加载器):

    • BootstrapClassLoader 是Java虚拟机(JVM)中最顶层的类加载器,它负责加载Java程序运行时需要的核心类库。这些类库位于<Java安装目录>/jre/lib目录下,包括 rt.jar 和所有的扩展类库,如 jsse.jar 和 ldap.jar。

    • 它是Java类加载器体系中的基础,其他的类加载器都是基于它来实现的

    • 处于安全考虑,Bootstrap 启动类加载器只加载包名为 java、javax、sun 等开头的类

    • 类加载器负责加载在 JAVA_HOME/jre/libsun.boot.class.path 目录中的,或者被 -Xbootclasspath 参数所指定的路径中的类,并且是虚拟机识别的类库加载到虚拟机内存中

    • 仅按照文件名识别,如 rt.jar 名字不符合的类库即使放在 lib 目录中也不会被加载

    • 由于 BootstrapClassLoader 是JVM实现者实现的,它不受Java的双亲委派模型的限制。它直接加载指定的类库,而不需要委派给父类加载器去完成

    • 启动类加载器无法被 Java 程序直接引用,编写自定义类加载器时,如果要把加载请求委派给启动类加载器,直接使用 null 代替

  • 扩展类加载器(Extension ClassLoader):

    • Extension ClassLoader 是 Java 中的一种特殊类型的 ClassLoader,负责从扩展目录加载类。这些目录通常包括lib/extJava 运行时环境中的目录,以及java.ext.dirs系统属性指定的任何其他目录。

    • 由 ExtClassLoader (sun.misc.Launcher$ExtClassLoader) 实现,上级为 Bootstrap,显示为 null

    • JAVA_HOME/jre/lib/ext 或者被 java.ext.dir 系统变量所指定路径中的所有类库加载到内存中

    • 开发者可以使用扩展类加载器,创建的 JAR 放在此目录下,会由扩展类加载器自动加载

    • Extension ClassLoader 是 的子类URLClassLoader,它用于从不属于 Java 平台的外部 JAR 文件加载类。这允许开发人员通过添加包含自定义类和库的附加 JAR 文件来扩展他们的 Java 应用程序的功能。

    • java.ext.dirs要使用扩展类加载器,您可以使用系统属性指定包含要加载的 JAR 文件的目录。然后您可以使用该ClassLoader.loadClass()方法从这些 JAR 文件中加载类。总的来说,Extension ClassLoader 是一个有用的工具,它允许您从外部 JAR 文件加载类,从而扩展您的 Java 应用程序的功能。

  • 应用程序类加载器(Application ClassLoader):

    • 可以直接使用这个类加载器,如果应用程序中没有自定义类加载器,这个就是程序中默认的类加载器

    • Application ClassLoader 是一种 Java ClassLoader,负责从应用程序类路径加载类。该类加载器是 的子类,URLClassLoader用于加载属于用户应用程序的类,以及应用程序所依赖的任何库和依赖项。

    • Application ClassLoader 通常是ClassLoader用户应用程序使用的父类加载器。这意味着当在用户的类路径中找不到某个类时,Application ClassLoader 会将类加载委托给它的父类加载器。

    • 由 AppClassLoader(sun.misc.Launcher$AppClassLoader) 实现,上级为 Extension

    • 负责加载环境变量 classpath 或系统属性 java.class.path 指定路径下的类库

    • 这个类加载器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值,因此称为系统类加载

    • 要使用应用程序类加载器,您可以使用java.class.path系统属性指定包含您的应用程序使用的类和库的目录和 JAR 文件。然后您可以使用该ClassLoader.loadClass()方法从这些位置加载类。总的来说,Application ClassLoader是Java类加载机制的重要组成部分,负责加载构成用户应用程序的类。

public static void main(String[] args) {
    //获取系统类加载器
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

    //获取其上层  扩展类加载器
    ClassLoader extClassLoader = systemClassLoader.getParent();
    System.out.println(extClassLoader);//sun.misc.Launcher$ExtClassLoader@610455d6

    //获取其上层 获取不到引导类加载器
    ClassLoader bootStrapClassLoader = extClassLoader.getParent();
    System.out.println(bootStrapClassLoader);//null

    //对于用户自定义类来说:使用系统类加载器进行加载
    ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
    System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

    //String 类使用引导类加载器进行加载的 --> java核心类库都是使用启动类加载器加载的
    ClassLoader classLoader1 = String.class.getClassLoader();
    System.out.println(classLoader1);//null

}

补充两个类加载器:

转载自:https://juejin.cn/post/7176967241122971703
评论
请登录