类与类加载器
把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。 实现这个动作的代码模块称为“类加载器”。
- 类加载器的作用:将class文件加载进JVM的方法区,并在方法区中创建一个java.lang.Class对象作为外界访问这个类的接口。
- 类与类加载器的关系:比较两个类是否相等,只有当这两个类由同一个加载器加载才有意义;否则,即使同一个class文件被不同的类加载器加载,那这两个类必定不同,即通过类的Class对象的equals执行的结果必为false。
类加载器种类
JVM提供如下三种类加载器:
-
启动类加载器 (Bootstrap ClassLoader)
负责加载Java_Home\lib中的class文件。 -
扩展类加载器 (Extension ClassLoader)
负责加载Java_Home\lib\ext目录下的class文件。 -
应用程序类加载器 (Application ClassLoader)
负责加载用户classpath下的class文件。
双亲委派模型
双亲委派模型除了要求顶层的启动类加载器外,其他的类加载器都应有自己的父类加载器,这里的类加载器之间的斧子关系一般不会以继承(Inheritance)的关系来实现,而是都是使用组合(Composition)关系来复用父加载器的代码。
类加载器的双亲委派模型如图所示:
- 工作过程:如果一个类加载器收到了加载类的请求,它首先将请求交由父类加载器加载;若父类加载器加载失败,当前类加载器才会自己加载类。
- 作用:像java.lang.Object这些存放在rt.jar中的类,无论使用哪个类加载器加载,最终都会委派给最顶端的启动类加载器加载,从而使得不同加载器加载的Object类都是同一个。
- 原理:双亲委派模型的代码在java.lang.ClassLoader类中的loadClass函数中实现,其逻辑如下:
- 首先检查类是否被加载;
- 若未加载,则调用父类加载器的loadClass方法;
- 若该方法抛出ClassNotFoundException异常,则表示父类加载器无法加载,则当前类加载器调用findClass加载类;
- 若父类加载器可以加载,则直接返回Class对象;