《深入理解java虚拟机》学习笔记二/双亲委派模型

来源:互联网 发布:信贷业务流程优化 编辑:程序博客网 时间:2024/05/16 13:03

本篇学习双亲委派模型。

类与类加载器
如何比较俩个类是否“相等”?
     对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在java虚拟机中的唯一性。
     也就是说,如果俩个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那么这俩个类必定不相等。
     这里所说的相等,包括代表类的Class对象的equals()方法,isAssignableFrom()方法,isInstance()方法的返回结果,也包括使用instanceof关键字做对象所属关系判定等情况。也就是说不同的类加载器对Class是有一定影响的。

双亲委派模型
从java虚拟机角度看有俩种不同的类加载器:
     一:启动类加载器(Bootstrap ClassLoader)                                               C++实现
     二:所有其他的类加载器(全部都继承自抽象类java.lang.ClassLoader)          java实现
从开发人员角度看:
启动类加载器Bootstrap ClassLoader
     作用:负责将存放在<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机中。启动类加载器无法被java程序直接引用,用户在编写自定义类加载时,如果需要把加载请求委派给引导类加载器,那直接使用null代替即可,
扩展类加载器Extension ClassLoader
     这个加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径的所有类库,开发者可以直接使用扩展类加载器
应用程序加载器Application ClassLoader
     这个类加载器是由sun.misc.Launcher$AppClassLoader实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称它为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库,开发者可以直接使用这个类加载器。如果应用程序中没有自定义自己的类加载器,一般情况下这个就是程序中默认的类加载器。

     我们的程序都是由这三种类加载器相互配合进行加载的,如果有必要,还可以加入自己定义的类加载器。
     它们的关系图如下:

双亲委派模型(JDK1.2后被引入)
     类加载器如果呈现这样的层次关系,我们称其为双亲委派模型(Parents Delegation Model)
     要求:
          除了顶层的启动类加载器外,其余的加载器都应有其自己的父类加载器,而且这里类加载器的父子关系一般都不是以继承(Inheritance)的关系来实现,而是以组合(Composition)的关系来复用父加载器的代码。
双亲委派模型的工作流程:
     当类加载器接收到类加载的请求时,它不会自己去尝试加载这个类,而是把这个请求委派给父加载器去完成,每一个层次的类加载器都是如此,因此所有的请求最终都应该传送到启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求(它的搜索范围内没有找到所需的类)时,子加载器才会尝试自己去加载。
     优点:java类随着它的类加载器一起具备了一种带有优先级的层次关系。
     举例:比如我们要加载java.lang.Object,它存放在rt.jar中,无论哪个类加载器要加载换个类,都会委派给处于模型最顶端的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类(上面提到了如何比较俩个类是否'相等')。相反,如果没有双亲委派模型,那么各个类加载器都去自行加载的话,那么在程序中就会出现多个Object类,导致应用程序一片混乱。

下面是双亲委派模型的实现,代码逻辑:
     首先检查是否已经被加载过
     如果没有加载过则调用父类的classLoader的方法
     如果父加载器为空则默认使用启动类加载器作为父加载器
     如果父类加载器加载失败,则抛出ClassNotFoundException异常后,再调用自己的findClass()方法进行加载
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;}

越基础的类由越上层的加载器进行加载,何为基础?就是总是作为被用户代码调用的API

0 0
原创粉丝点击