在了解双亲委派模型之前,我们先来看看虚拟机中存在哪些类加载器。
类加载器(4种)
在虚拟机中存在4种类加载器,分别是启动类加载器、扩展类加载器、应用程序类加载器和自定义类加载器。前面三种是Java虚拟机预定义的类加载器,最后一种是我们通过继承ClassLoader抽象类实现的类加载器。
-
启动类加载器(Bootstrap ClassLoader):最顶层的类加载器,主要加载核心类库,即
%JRE_HOME%\lib下面的类库。例如rt.jar、resources.jar、charsets.jar等。 -
扩展类加载器(Extension ClassLoader):扩展的类加载器,用于加载
%JRE_HOME%\lib\ext目录下的jar包和class文件。 -
应用程序类加载器(Application ClassLoader):也叫作系统类加载器(System ClassLoader)。用于加载当前应用的classpath的所有类。
-
自定义类加载器:由开发人员自己定义的类加载器。
类加载器之间的关系
双亲委派模型
-
当一个类加载器收到类加载任务的时候,不会先自己加载,而是将这个类加载任务交给其父类加载器来完成,以此类推。
-
当父类加载器无法完成这个类加载任务的时候,才自己完成这个类加载任务。
使用双亲委派模型的好处
- 确保类的全局唯一性。例如:加载位于rt.jar包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个Object对象。
这里涉及到了一个叫做命名空间的问题。
- 更加安全。解决了各个类加载器的基础类的统一问题,如果不使用该种方式,那么用户可以随意定义类加载器来加载核心api,会带来相关隐患。
命名空间
命名空间是由该类加载器及其父类加载器构成的。在该命名空间中,父类加载器加载的类对子类是可见的,但是子类加载器加载的类对父类加载器不可见,而且在同一命名空间中一定不会出现多个相同的Class对象(双亲委派模型的原因)。
这里注意一下,虚拟机预定义的三个类加载器是符合双亲委派模型的。但是我们自定义的类加载器可以遵循双亲委派模型,也可以破坏双亲委派模型。如果破坏双亲委派模型的,那么就会存在多个命名空间的情况。