类的加载机制

类的加载器

    类加载器(ClassLoader),即加载类的东西。在我们使用一个类之前,JVM(JAVA虚拟机)需要先将该类的字节码文件(.class文件)从磁盘、网络或其他来源加载到内存中,并对字节码进行解析生成对应的Class对象,这就是类加载器的功能。我们可以利用类加载器,实现类的动态加载。

    类的字节码可以来自于磁盘文件 *.class,也可以是 jar 包里的 *.class,也可以来自远程服务器提供的字节流,字节码的本质就是一个字节数组 []byte,它有特定的复杂的内部格式。

类的加载机制_第1张图片

延迟加载

    JVM 运行并不是一次性加载所需要的全部类的,它是按需加载,也就是延迟加载。程序在运行的过程中会逐渐遇到很多不认识的新类,这时候就会调用 ClassLoader 来加载这些类。加载完成后就会将 Class 对象存在 ClassLoader 里面,下次就不需要重新加载了。比如你在调用某个类的静态方法时,首先这个类肯定是需要被加载的,但是并不会触及这个类的实例字段,那么实例字段的类别 Class 就可以暂时不必去加载,但是它可能会加载静态字段相关的类别,因为静态方法会访问静态字段。而实例字段的类别需要等到你实例化对象的时候才可能会加载。

各司其职

JVM 运行实例中会存在多个 ClassLoader,不同的 ClassLoader 会从不同的地方加载字节码文件。JVM 中内置了三个重要的 ClassLoader,分别是:

BootStrap ClassLoader:负责加载 JVM 运行时核心类,这些类位于 JAVA_HOME/lib/rt.jar 文件中,我们常用内置库 java.xxx.* 都在里面,比如 java.util.*、java.io.*、java.nio.*、java.lang.* 等等。这个 ClassLoader 比较特殊,它是由 C 代码实现的,我们将它称之为「根加载器」。

Extension ClassLoader:称为扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。比如 swing 系列、内置的 js 引擎、xml 解析器 等等,这些库名通常以 javax 开头。

App ClassLoader:称为系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件。我们自己编写的代码以及使用的第三方 jar 包通常都是由它来加载的。main 方法执行的时候,这第一个用户类的加载器就是 AppClassLoader。

    jdk 内置了一个 URLClassLoader,用户只需要传递规范的网络路径给构造器,就可以使用 URLClassLoader 来加载远程类库和本地类库。ExtensionClassLoader 和 AppClassLoader 都是 URLClassLoader 的子类,从本地文件系统里加载类库。

ClassLoader 传递性

    程序在运行过程中,遇到了一个未知的类,虚拟机的策略是使用调用者 Class 对象(正在运行一个方法调用,这个方法挂在哪个类上面,那这个类就是调用者 Class 对象)的 ClassLoader 来加载当前未知的类。每个 Class 对象里面都有一个 classLoader 属性记录了当前的类是由谁来加载的。因为 ClassLoader 的传递性,所有延迟加载的类都会由初始调用 main 方法的这个 ClassLoader 全全负责,它就是 AppClassLoader。

双亲委派

     AppClassLoader 只负责加载 Classpath 下面的类库,如果遇到没有加载的系统类库怎么办,AppClassLoader 必须将系统类库的加载工作交给 BootstrapClassLoader 和 ExtensionClassLoader 来做,这就是双亲委派。这三个 ClassLoader 之间形成了级联的父子关系,每个 ClassLoader 都很懒,尽量把工作交给父亲做,父亲干不了了自己才会干。每个 ClassLoader 对象内部都会有一个 parent 属性指向它的父加载器。

类的加载机制_第2张图片


总结:加载流程如下图

类的加载机制_第3张图片

参考:https://mp.weixin.qq.com/s/HZEFKZXu_AUr4HqD7M2H0g

你可能感兴趣的:(类的加载机制)