双亲委派(Parent Delegation)是一种软件设计模式,常用于Java类加载器的实现。它通过继承关系来实现类的加载,即每个类加载器都有一个父加载器,当一个类加载器需要加载一个类时,它首先将该任务委派给它的父加载器,只有在父加载器无法加载时,才由该加载器自己来完成加载。
双亲委派的介绍
站在Java虚拟机的角度讲,只存在两种不同的类加载器:一种是启动类加载器
(Bootstrap ClassLoader),这个类加载器使用C++语言实现[2],是虚拟机自身的一部分;另外一种就是所有其他的类加载器
,这些类加载器都由Java语言实现,独立于虚拟机外部,并且全都继承自抽象类java.lang.ClassLoader。
从Java开发人员的角度来看,类加载器就还可以划分得更细致一些,绝大部分Java程序都会使用到以下三种系统提供的类加载器: 启动类加载器
(Bootstrap ClassLoader):前面已经介绍过,这个类加载器负责将存放在<JAVA_HOME>\lib
目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机内存中。启动类加载器无法被Java程序直接引用。 扩展类加载器
(Extension ClassLoader):这个加载器由sun.misc.LauncherKaTeX parse error: Undefined control sequence: \lib at position 34: …负责加载<JAVA_HOME>\̲l̲i̲b̲\ext目录中的,或者被jav…AppClassLoader来实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称它为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
双亲委派的优点:
使用双亲委派模型来组织类加载器之间的关系,有一个显而易见的好处就是Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存放在rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果没有使用双亲委派模型,由各个类加载器自行去加载的话,如果用户自己写了一个名为java.lang.Object的类,并放在程序的ClassPath中,那系统中将会出现多个不同的Object类,Java类型体系中最基础的行为也就无从保证,应用程序也将会变得一片混乱。如果您有兴趣的话,可以尝试去写一个与rt.jar类库中已有类重名的Java类,将会发现可以正常编译,但永远无法被加载运行。
示例代码:
双亲委派模型对于保证Java程序的稳定运作很重要,但它的实现却非常简单,实现双亲委派的代码都集中在java.lang.ClassLoader的loadClass()方法之中,如代码逻辑清晰易懂:先检查是否