扫码关注微信公众号

回复“面试手册”,获取本站PDF版

回复“简历”,获取高质量简历模板

回复“加群”,加入程序员交流群

回复“电子书”,获取程序员类电子书

当前位置: Java > JVM高频面试题 > 23.什么是双亲委派机制

双亲委派机制是面试中非常高频的一个知识点,需要牢牢掌握

双亲委派机制:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一层次的类加载器都是这样,所以所有的加载请求最终都应该传送到顶层的启动类加载容器,只有当父类加载器无法完成加载时,子加载器才会尝试自己去加载,如下图

双亲委派机制
双亲委派机制

这里有个问题,类加载器中的父类加载器和子类加载器是继承关系吗?

既然问了,那肯定就不是了,在双亲委派模型中,类加载器之间的父子关系一般不是以继承关系实现的,而是组合的关系来复用父加载器的代码的

介绍完双亲委派的概念,那双亲委派机制有什么好处呢?

双亲委派的保证了Java程序稳定地运行,可以避免类地重复加载(父类加载器加载过,子加载器不会再进行加载),保证Java的核心API不被篡改,例如,你自己编写了一个java.lang.Object类,也不会被加载,因为根据双亲委派机制,会由启动类加载器进行加载,会先加载位于rt.jar中的java.lang.Object类,并且其他子类加载器不会再去加载ava.lang.Object类。

那双亲委派机制的弊端是什么呢?

从上面的介绍可以看到父类加载器的优先级是大于子类加载器的,只有父类加载器无法加载,子类加载器才会去尝试加载,这在大多数情况是没有问题的,因为越上层加载的类通常是基础类(像Object类),一般情况这些基础类都是被用户代码所调用的API,但基础类要是想调用用户的代码,那就会出问题了,因为第三方的类不能被启动类加载器加载。

举个很经典的例子,JDBC服务在Java开发中非常常见(操作数据库),

Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "lurenzhang", "666");

DriverManager类是在java.sql包中,java.sql包的位置是jdk\jre\lib\rt.jar,也就是DriverManager类会先被启动类加载器加载,类在加载时其中有这样一段代码

ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);

这会尝试加载classpath下面的所有实现了Driver接口的实现类,而实现了Driver接口的第三方类库应由应用类加载器加载,这样一来启动类加载器加载的类使用了启动类加载器加载的类,违背双亲委派机制的原理。

如何破坏双亲委派机制

这个需要先去了解双亲委派是怎么实现的,看下java.lang.ClassLoader的loadClass()源码就知道了,这里就不展开写了,想破环双亲委派自定义一个类加载器,重写其中的loadClass()方法即可。


点击面试手册,获取本站面试手册PDF完整版