一面腾讯提问:如果我自定义一个 new Object 类,请问这个类是否会被加载?
回答:不会,因为双亲委派,向上加载。回答的过程中磨磨唧唧。当然最后一面也是没有过。
总之一句话:向上加载,向下委派.
根据代码可见,就是loadclass递归调用,首先依次向上查找,向下委派。
详细解释:当一个类加载器收到加载任务时,会先交给自己的父加载器去完整,因此最终的加载的人任务都会交给最顶层的BootstrapClassLoader,只有当父加载器无法完成加载,才反馈进行递归回溯,此时子类加载的时候,就是通过调用对应的findClass(name)去加载,子类依次回溯加载。
接下来分别解释:这三层加载器的作用:
- 启动类加载器(Bootstrap ClassLoader)
- 扩展类加载器(Extension ClassLoader)
- 应用类加载器(Application ClassLoader)
启动类加载器:内嵌在JVM内核的加载器,用C++语言编写(因此也不会继承ClassLoader),是类加载器中层次中最顶层的加载器。用于java的核心类库,即加载jre/lib/rt.jar包里面的数据。
扩展类加载器:它负责加载jre扩展目录的jar
应用类加载器:主要负责加载应用程序的主函数类。 ClassLoader.getSystemClassLoader()方法可以获取此类加载器的实例,系统类加载器也因此得名。应用类加载器主要加载classpath下的class。
上面已经解释了清楚了整个具体的流程:
接下来解释: 父类委派的优点是什么? 如何打破 父类委派。
如何打破 父类委派?
首先自定义的类加载器 MyClassLoder extends ClassLoader。然后重写 loadclass方法。可以参考下面的demo来实现。
上图就是ClassLoder类中给我们自定义NetworkClassLoader的demo。
我们整理ClassLoader里面具体的整体流程:
1:loadclass:双亲委派机制,子类加载器委托父类加载器加载,父类加载器都加载失败时,子类加载器通过findclass自行加载
2:findclass: 当前类加载器的根据路径以及class文件名称加载字节码,从clas文件中读取字节数组,然后hi用defineClass。
3:defineclass:根据字节数组,返回class对象。
父类双亲委派作用:
1:保证JVM的核心类和用户的类都能得到正常加载。或者说为了防止 findclass和defineclass对象覆盖标准库中的类对象,避免产生安全风险。
但发展会带来创新,创新就会带来变革,jdbc与tomcat打破了这个自古相传的机制。
在jdbc中,父加载器委托子加载器。即利用线程上下文类加载器,让启动类加载器得以委托应用类加载器,去加载jar中的数据库驱动。