ClassLoader
顾名思意,类加载器。
它负责将 Class 的字节码形式转换成内存形式的 Class 对象
JVM和ClassLoader有什么关系?
JVM运行实例中存在多个ClassLoader
JVM 中内置了三个重要的 ClassLoader,分别是 BootstrapClassLoader、ExtensionClassLoader 和 AppClassLoader。
BootstrapClassLoader 负责加载 JVM 运行时核心类,这些类位于 JAVA_HOME/lib/rt.jar 文件中,我们常用内置库 java.xxx.* 都在里面,比如 java.util.、java.io.、java.nio.、java.lang. 等等。这个 ClassLoader 比较特殊,它是由 C 代码实现的,我们将它称之为「根加载器」。
ExtensionClassLoader 负责加载 JVM 扩展类,比如 swing 系列、内置的 js 引擎、xml 解析器 等等,这些库名通常以 javax 开头,它们的 jar 包位于 JAVA_HOME/lib/ext/*.jar 中,有很多 jar 包。
AppClassLoader 才是直接面向我们用户的加载器,它会加载 Classpath 环境变量里定义的路径中的 jar 包和目录。我们自己编写的代码以及使用的第三方 jar 包通常都是由它来加载的。
当我们的 main 方法执行的时候,这第一个用户类的加载器就是 AppClassLoader。例如下图
AppClassLoader实例化的时候,classer中就已经有值了,存储了,该Classpath中找到的类名列表。
ClassLoader之间的加载顺序关系
AppClassLoader 在加载一个未知的类名时,它并不是立即去搜寻 Classpath,它会首先将这个类名称交给 ExtensionClassLoader 来加载
而 ExtensionClassLoader 在加载一个未知的类名时,它也并不是立即搜寻 ext 路径,它会首先将类名称交给 BootstrapClassLoader 来加载
这三个 ClassLoader 之间形成了级联的父子关系,每个 ClassLoader 都很懒,尽量把工作交给父亲做,父亲干不了了自己才会干。每个 ClassLoader 对象内部都会有一个 parent 属性指向它的父加载器。
class ClassLoader {
...
private final ClassLoader parent;
...
}
class Class{
private final ClassLoader classLoader;
...
}
classLoader\parent为null时,代表这个类也是「根加载器」加载的。
Classpath
classpath是JVM用到的一个环境变量,它用来指示JVM如何搜索class。
因为Java是编译型语言,源码文件是.java,而编译后的.class文件才是真正可以被JVM执行的字节码。因此,JVM需要知道,如果要加载一个abc.xyz.Hello的类,应该去哪搜索对应的Hello.class文件。
getSystemClassLoader()方法
AppClassLoader 可以由 ClassLoader 类提供的静态方法 getSystemClassLoader() 得到
ClassLoader 传递性
程序在运行过程中,遇到了一个未知的类,它会选择哪个 ClassLoader 来加载它呢?虚拟机的策略是使用调用者 Class 对象的 ClassLoader 来加载当前未知的类。何为调用者 Class 对象?就是在遇到这个未知的类时,虚拟机肯定正在运行一个方法调用(静态方法或者实例方法),这个方法挂在哪个类上面,那这个类就是调用者 Class 对象。前面我们提到每个 Class 对象里面都有一个 classLoader 属性记录了当前的类是由谁来加载的。
因为 ClassLoader 的传递性,所有延迟加载的类都会由初始调用 main 方法的这个 ClassLoader 全全负责,它就是 AppClassLoader。
如何查看当前JVM中有多少个ClassLoader
Class类中
存在属性 classLoader,标识自己的类加载器。
class Class<T> {
...
private final ClassLoader classLoader;
...
}
Class.forName
为什么Class.forName(…)能得到一个类的实例
该方法中,重要的参数有ClassLoader,
最终进入一个native方法了。
此时,我们知道,把一个类通过名字转化Java内存中的一个实例对象,需要通过ClassLoader。
.java和.class有什么区别
.java:代表java源文件
.class:字节码文件,由.java源文件通过javac命令编译后生成的文件。是可以运行在任何支持Java虚拟机的硬件平台和操作系统上的二进制文件
缓存
ClassLoader加载类之后会有缓存