关于双亲委派机制你不得不知道的事

什么是双亲委派机制?

面试高频题,之前面试的时候也被问过。那么什么是双亲委派机制呢?

简单来说,就是一个类在被加载的时候,首先会将加载请求委派给父加载器,如果当父加载器反馈无法加载的时候,子类才会自己去加载。

这里我们举一个例子更加容易理解
我在src目录下建一个lang包,建一个String类,大家应该都知道这是不行的,为什么不行?因为java已经有了String类了,所以运行自己写的String类的时候他会报一个错误,就是说找不到main方法。



这就很奇怪了,我们明明写了main方法啊?其实这就是因为双亲委派机制才会这样。我们在加载类的时候委派给父类加载器直到启动类加载器,但是在启动类加载器下,已经加载过String类了,里面并没有main方法,所以才会报此错误。在下面介绍了类加载器就更容易明白了。

类加载器的类别

那么类加载器有几种呢?我们其实可以用代码直接查看的。我们定义一个test类,去查看它的加载器以及父类加载器


可以看到我们的当前的加载器,是AppClassLoader,父类加载器是ExtClassLoader,而爷类加载器为null,为什么是null呢?说明访问不到吧,这是因为这个类加载器不是用java写的,是c/c++写的,java访问不到所以就是null。这个类加载器就是最上面的加载器BootstrapClassLoader

所以我们可以将类加载器分为以下几种

BootstrapClassLoader(启动类加载器)

在jdk的rt.jar包下面,是所有类加载器的父类,c++编写的。涉及到虚拟机的具体实现无法引用到,这也就是我们上面为什么null的原因了。

ExtClassLoader (标准扩展类加载器)

负责加载Java的扩展类库,也就是从jre/lib/ext目录下或者java.ext.dirs系统属性指定的目录下加载类。

AppClassLoader(系统类加载器)

负责加载加载应用程序的主函数类

CustomClassLoader(用户自定义类加载器)

顾名思义,是用户自己编写的类加载器,用来加载指定路径下面的类

双亲委派机制流程

不考虑自定义的类加载器,我们首先会在加载AppClassLoader,如果加载过了,则不加载,如果没有加载,则委派给了ExtClassLoader,到了这里,也会同样进行判断,如果没有被加载的话,则会被委派给了BootstrapClassLoader。在启动类类加载器这里,如果被加载过的话,就不加载了,如果没有的话但是可以加载,就进行加载了,如果不可以加载就反馈给了子加载器,一直到系统类加载器。

双亲委派机制流程图

常见面试题

双亲委派机制的作用(为什么需要双亲委派机制?

1、防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。
2、保证核心.class不能被篡改。通过委托方式,不会去篡改核心.class,即使篡改也不会去加载,即使加载也不会是同一个.class对象了。不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。

什么是双亲委派模型的破坏?

双亲委派模型的破坏指的是不按照双亲委派模型来加载类,比如JNDI,它的代码由启动类加载器加载,但JDNI需要调用部署在ClassPath的JNDI接口,但启动类加载器是不知道这些代码的,所以就有了线程上下文类加载器(Thread Context ClassLoader),可以通过java.lang.Thread类setContextClassLoader设置类加载器,通过这个加载器父加载器就可以请求子类加载器完成类加载的动作。

能不能自己写一个java.lang.System?(java.lang.String)

我们上面说过是不可以的,这是通常来说。但是还有我们一直没怎么讲的自定义类加载器,我们其实是可以通过自定义类加载器来加载的。系统自带的类加载器都会加载特定目录下的类,我们只要把类放到特定的路径让系统加载不到,然后通过自己的自定义类加载器就可以加载。

部分参考知识来源于
https://www.jianshu.com/p/1e4011617650
https://blog.csdn.net/codeyanbao/article/details/82875064
https://www.yuque.com/itsaysay/mzsmvg/poqsxq#b18bda7d
《深入理解java虚拟机3》

你可能感兴趣的:(关于双亲委派机制你不得不知道的事)