什么是双亲委派?
在 Java 虚拟机中,任何一个类由加载它的类加载器和这个类一同来确立其唯一性。
也就是说,JVM 对类的唯一标识,可以简单的理解为由ClassLoader id + PackageName + ClassName组成,因此在一个运行程序中有可能存在两个包名和类名完全一致的类,但是如果这两个类不是由一个 ClassLoader 加载,会被视为两个不同的类,此时就无法将一个类的实例强转为另外一个类,这就是类加载器的隔离性。
为了解决类加载器的隔离问题,JVM 引入了双亲委派模型。
双亲委派模式,可以用一句话来说表达:任何一个类加载器在接到一个类的加载请求时,都会先让其父类进行加载,只有父类无法加载(或者没有父类)的情况下,才尝试自己加载。
大致流程图如下:
图片
使用双亲委派模式,可以保证,每一个类只会有一个类加载器。例如 Java 最基础的 Object 类,它存放在 rt.jar 之中,这是 Bootstrap 的职责范围,当向上委派到 Bootstrap 时就会被加载。
但如果没有使用双亲委派模式,可以任由自定义加载器进行加载的话,Java 这些核心类的 API 就会被随意篡改,无法做到一致性加载效果。
JDK 中ClassLoader.loadClass()类加载器中的加载类的方法,部分核心源码如下:
如何自定义类加载器?
针对某些特定场景,比如通过网络来传输 Java 类的字节码文件,为保证安全性,这些字节码经过了加密处理,这时系统提供的类加载器就无法对其进行加载,此时我们可以自定义一个类加载器来完成文件的加载。
自定义类加载器也需要继承ClassLoader类,简单示例如下:
相关的测试类如下:
将ClassLoaderTest.java源文件放在指定目录下,并通过javac命令编译成ClassLoaderTest.class,最后进行测试。
输出结果:
在实际使用过程中,最好不要重写loadClass方法,避免破坏双亲委派模型。
小结
双亲委派,指的是在接受类加载请求时,会让父类加载器试图加载该类,只有在父类加载器无法加载该类或者没有父类时,才尝试从自己的类路径中加载该类。
其次,针对某些场景,如果要实现类的隔离,可以自定义类加载器来实现特定类的加载。