文章目录
- 1、何为类加载器
- 2、三层类加载器
- 3、双亲委派模型
参考资料:《深入理解Java虚拟机》
1、何为类加载器
类加载过程中,加载阶段第一步操作就是通过一个类的全限定名获取此类的二进制字节流。实现这个动作的代码就是类加载器。
任意一个类都必须由加载它的类加载器和这个类本身共同确定类在JVM中的唯一性,每个类加载器都拥有独立的类名称空间;所以即使两个类来自于同一个Class文件,被同一个JVM加载,只要加载它们的类加载器不同,这两个类就必定不相等。
站在Java虚拟机角度来看,只存在两种不同的类加载器:
- 启动类加载器(Bootstrap ClassLoader):C++语言实现,是虚拟机一部分
- 其他所有的类加载器:Java语言实现,独立存在于虚拟机外部,全部继承于抽象类
java.lang.ClassLoader
2、三层类加载器
JDK9之前,绝大多数Java应用都会使用一下三个系统提供的类加载器进行加载:
- 启动类加载器(Bootstrap Class Loader):负载加载存放
JAVA_HOME\lib
目录,或者被-Xbootclasspath
参数所指定的路径中存放的类加载到JVM内存中。启动类加载器无法被Java程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给启动类加载器,那直接使用null
代替即可。- 扩展类加载器(Extension Class Loader):该加载器是在类
sun.misc.Launcher$ExtClassLoader
中Java代码的形式实现的。负责加载JAVA_HOME\lib\ext
目录中,或者被java.ext.dirs
系统变量所指定的路径中所有的类库。JDK开发团队允许用户将具有通用性的类库放置在ext目录里,以拓展Java
SE的能力。- 应用类加载器(Application Class Loader):该加载器是在类
sun.misc.Launcher$AppClassLoader
来实现。负责加载用户类路径ClassPath
上所有的类库。如果应用程序中没有自定义类加载器,那么它就是程序默认的类加载器。
当然还可以加入自定义类加载器进行拓展,例如:
- 增加除磁盘位置之外的Class文件来源
- 通过类加载器实现类的隔离、重载等功能
3、双亲委派模型
第2节中的图片被称作双亲委派模型。
双亲委派模型的工作过程:
如果一个类加载器收到类加载的请求,它首先不会自己尝试加载,而是把这个请求向上委派给父类加载器,每一层都是如此(孔融让梨);因此所有的加载请求最终应该传送到最顶层的启动类加载器中,只有当父加载器反馈无法完成本次加载请求,子加载器才会尝试加载。
使用双亲委派模型的好处:
Java中的类随着它的类加载器具备了优先级的层次关系。例如
java.lang.Object
类存放在tr.jar中,无论哪个类加载器要加载这个类,最终都是委派给最上层的启动类加载器进行加载,因此Object类在各种类加载器环境中都能保证是同一个类。
反之,没有双亲委派模型,用户编写java.lang.Object
类放在ClassPath中,这样系统会出现不同的Object类,会变得一片混乱。