首页 > 编程知识 正文

双亲委派机制优缺点,破坏双亲委派模型

时间:2023-05-03 20:29:13 阅读:31139 作者:3205

父母一说要委托模特,就必须从班级加载器开始。 。

Java虚拟机类加载过程是将Class类文件加载到内存中,然后验证、转换分析和初始化Class文件中的数据,使其最终成为可直接在虚拟机中使用的Java类型的过程。

在加载阶段,java虚拟机必须完成以下三项:

a .从类的完全限定名称中获取定义该类的二进制字节流。

b .将定义类的以二进制字节流为代表的静态存储结构转换为方法区域的运行时数据结构。

c .在java堆中生成表示类的java.lang.Class对象,作为访问方法区域数据的入口。

类的加载过程由类加载器完成。

在Java中,任何一个类都必须由装载它的类加载器和该类本身决定它在Java虚拟机中的唯一性。 也就是说,比较两个类是否相等的前提是两个类由同一类加载器加载。 否则,即使两个类来自同一Class类文件,只要加载的类加载器不同,就没有意义。 这两个班不一定相等。 此处的等效内容包括表示类的Class对象的equals (方法、isAssignableFrom )方法、isInstance方法和instanceof关键字的结果。

请看看以下示例:

package com.hfax.com mon.depository.front.test; import java.io.IOException; import java.io.InputStream; 公共类测试2 (publicstaticvoidmain (字符串[ ] args ) throwsexception(//匿名内部类实现自定义类加载器finalclassloadermyclassloader=newc loader find class (字符串名称) throwsclassnotfoundexception(/获取类文件名stringfilename=name.substring ) name.lastindexof ) '.'的InputStream in=getClass ().getresourceasstream try { byte [ ] b=new byte [ in.available (]; returndefineclass(name,b,0,b.length ); }字符识别(ioexceptione ) thrownewclassnotfoundexception ) name; }; }; objectobj=my class loader.load class (com.hfax.com mon.depository.front.test.test2) ).newInstance ); system.out.println (obj.getclass () ); system.out.println (objinstance ofcom.hfax.com mon.depository.front.test.test2); }

0px;padding-bottom:0px;font-family:Arial;line-height:26px;">输出结果如下:

com.test.ClassLoaderTest

false (jdk1.2版本以后引入了双亲委派模型后,此时会返回true,想得到false结果的小伙伴可以用1.2以前的版本测试)

之所以instanceof会返回false,是因为com.test.ClassLoaderTest类默认使用Application ClassLoader加载,而obj是通过自定义类加载器加载的,类加载不相同,因此不相等。


说到这里就轮到双亲委派模型出场了。

先看双亲委派模型的经典体系统:


做一个简单解释:

(1).BootStrap ClassLoader:启动类加载器,负责加载存放在%JAVA_HOME%lib目录中的,或者通被-Xbootclasspath参数所指定的路径中的,并且被java虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库,即使放在指定路径中也不会被加载)类库到虚拟机的内存中,启动类加载器无法被java程序直接引用。

(2).Extension ClassLoader:扩展类加载器,由sun.misc.Launcher$ExtClassLoader实现,负责加载%JAVA_HOME%libext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。

(3).Application ClassLoader:应用程序类加载器,由sun.misc.Launcher$AppClassLoader实现,负责加载用户类路径classpath上所指定的类库,是类加载器ClassLoader中的getSystemClassLoader()方法的返回值,开发者可以直接使用应用程序类加载器,如果程序中没有自定义过类加载器,该加载器就是程序中默认的类加载器。


这里需要注意的是上述三个JDK提供的类加载器虽然是父子类加载器关系,但是没有使用继承,而是使用了组合关系。

从JDK1.2开始,java虚拟机规范推荐开发者使用双亲委派模式(ParentsDelegation Model)进行类加载,其加载过程如下:

(1).如果一个类加载器收到了类加载请求,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器去完成。

(2).每一层的类加载器都把类加载请求委派给父类加载器,直到所有的类加载请求都应该传递给顶层的启动类加载器。

(3).如果顶层的启动类加载器无法完成加载请求,子类加载器尝试去加载,如果连最初发起类加载请求的类加载器也无法完成加载请求时,将会抛出ClassNotFoundException,而不再调用其子类加载器去进行类加载。

双亲委派 模式的类加载机制的优点是java类它的类加载器一起具备了一种带优先级的层次关系,越是基础的类,越是被上层的类加载器进行加载,保证了java程序的稳定运行。双亲委派模式的实现:

protected synchronized Class<?> loadClass(String name, Boolean resolve) throws ClassNotFoundException{ //首先检查请求的类是否已经被加载过 Class c = findLoadedClass(name); if(c == null){ try{ if(parent != null){//委派父类加载器加载 c = parent.loadClass(name, false); } else{//委派启动类加载器加载 c = findBootstrapClassOrNull(name); } }catch(ClassNotFoundException e){ //父类加载器无法完成类加载请求 } if(c == null){//本身类加载器进行类加载 c = findClass(name); } } if(resolve){ resolveClass(c); } return c;}
通过双亲委派模型我们就能很好解决文章开始我们自定义的类加载器所出现的问题。

这里需要注意的是在JDK1.2之前,类加载尚未引入双亲委派模式,因此实现自定义类加载器时常常重写loadClass方法,提供双亲委派逻辑,从JDK1.2之后,双亲委派模式已经被引入到类加载体系中,自定义类加载器时不需要在自己写双亲委派的逻辑,因此不鼓励重写loadClass方法,而推荐重写findClass方法。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。