文章目录
- 1. 类的加载机制
- 2. 类的加载过程
- 3. 类与类加载器
- 4. 类加载器
- 5. 双亲委派模型
1. 类的加载机制
Java 虚拟机将 Java 类加载到内存的过程。
-
Java 源文件
通过 编译
生成 class文件
- 类加载器 ClassLoader 会读取这个 .class 文件, 并将其转换为 java.lang.Class 的实例。 有了该实例, JVM 就可以用它来创建对象, 调用方法等操作了。
2. 类的加载过程
类从被加载到虚拟机内存中开始, 到卸载出内存为止,它的整个生命周期包括:
加载、验证、准备、解析、初始化、使用以及卸载
7个阶段, 其中验证、准备、解析3个阶段统称为连接。
3. 类与类加载器
对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器都拥有一个独立的类名称空间。因此, 比较两个类是否"相等", 只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。
不同类加载器对 instanceof
关键字运算结果的影响
程序运行输出
4. 类加载器
从Java虚拟机的角度来讲, 只存在两种不同的类加载器: 一种是启动类加载器, 这个类加载器使用C++语言实现,是虚拟机自身的一部分;另一种是其他类加载器,这些类加载器都是由java语言实现,独立于虚拟机外部,并且全部都是继承自抽象类java.lang.ClassLoader。
- 启动类加载器:
BootStrap ClassLoader
负责将存放在 <JAVA_HOME>/lib
目录中的 或者 被 -Xbootclasspath 参数所指定
的路径中的类库加载到虚拟机内存中。 - 扩展类加载器:
Extension ClassLoader
负责加载 <JAVA_HOME>/lib/ext
目录中的 或者 被 java.ext.dirs 系统变量
所指定的路径中的所有类库。 - 应用程序类加载器:
Application ClassLoader
负责加载用户类路径(classpath)上
所指定的类库, 如果应用程序没有自定义过自己的类加载器, 一般情况下这个就是程序中默认的类加载器。
5. 双亲委派模型
双亲委派模型工作过程
: 如果一个类加载器收到了类加载的请求, 它首先不会尝试自己去加载这个类, 而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传到顶层的启动类加载器中, 只有当父类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时, 子加载器才会尝试自己去加载。使用双亲委派模型来组织类加载器之间的关系, 有一个显而易见的
好处就是 Java 类随着它的类加载器一起具备了一种带有优先级的层次关系
。 比如类 java.lang.Object, 它存放在 rt.jar 中, 无论哪一个类加载器要加载这个类, 最终都是委派给处于模型最顶层的启动类加载器进行加载,因此 Object 类在程序的各种类加载器环境中都是同一个类。相反, 如果没有使用双亲委派模型,由各个类加载器自行去加载的话,如果用户自己编写了一个为 java.lang.Object 的类, 并放在程序的 classpath 中, 那系统中将会出现多个不同的 Object 类, java 类型体系中最基础的行为也就无法保证, 应用程序也将会变得一片混乱。截至至今, 双亲委派模型出现过
3次较大规模的"被破坏"情况
。 第一次出现在 JDK1.2 发布之前, 因为双亲委派模型是在 JDK1.2 之后才被引入。而加载器和抽象类 java.lang.ClassLoader 则在 JDK1.0 时代就已经存在。第二次是由于这个模型自身的缺陷所导致的。第三次是由于用户对代码热替换,模块热部署的追求所导致的。具体信息请自行查阅相关资料了解。