1.什么是类加载器?java
在类加载阶段,有一步是“经过类的全限定名来获取描述此类的二进制字节流”,而所谓的类加载器就是实现这个功能的一个代码模块,这个动做是在Java虚拟机外部实现的,这样作可让应用程序本身决定如何去获取所须要的类。学习
类加载器的做用:首先类加载器能够实现最本质的功能即类的加载动做。同时,它还可以结合java类自己来肯定该类在Java虚拟机中的惟一性。用通俗的话来讲就是:比较两个类是否相等,只有这两个类是由同一个类加载器加载才有意义。不然,即便这两个类是来源于同一个Class文件,只要加载它们的类加载器不一样,那么这两个类一定不相等。spa
2.双亲委派模型继承
从虚拟机的角度来讲,只存在两种不一样的类加载器:一种是启动类加载器(Bootstrap ClassLoader),该类加载器使用C++语言实现,属于虚拟机自身的一部分。另一种就是全部其它的类加载器,这些类加载器是由Java语言实现,独立于JVM外部,而且所有继承自抽象类java.lang.ClassLoader。内存
从Java开发人员的角度来看,大部分Java程序通常会使用到如下三种系统提供的类加载器:开发
1)启动类加载器(Bootstrap ClassLoader):负责加载JAVA_HOME\lib目录中而且能被虚拟机识别的类库到JVM内存中,若是名称不符合的类库即便放在lib目录中也不会被加载。该类加载器没法被Java程序直接引用。源码
2)扩展类加载器(Extension ClassLoader):按《深刻理解java虚拟机》这本书上所说,该加载器主要是负责加载JAVA_HOME\lib\ext目录中的类库,可是貌似在JDK的安装目录下,没看到该指定的目录。该加载器能够被开发者直接使用。虚拟机
3)应用程序类加载器(Application ClassLoader):该类加载器也称为系统类加载器,它负责加载用户类路径(Classpath)上所指定的类库,开发者能够直接使用该类加载器,若是应用程序中没有自定义过本身的类加载器,通常状况下这个就是程序中默认的类加载器。it
咱们的应用程序都是由这三类加载器互相配合进行加载的,咱们也能够加入本身定义的类加载器。这些类加载器之间的关系以下图所示:io
如上图所示的类加载器之间的这种层次关系,就称为类加载器的双亲委派模型(Parent Delegation Model)。该模型要求除了顶层的启动类加载器外,其他的类加载器都应当有本身的父类加载器。子类加载器和父类加载器不是以继承(Inheritance)的关系来实现,而是经过组合(Composition)关系来复用父加载器的代码。
双亲委派模型的工做过程为:若是一个类加载器收到了类加载的请求,它首先不会本身去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每个层次的加载器都是如此,所以全部的类加载请求都会传给顶层的启动类加载器,只有当父加载器反馈本身没法完成该加载请求(该加载器的搜索范围中没有找到对应的类)时,子加载器才会尝试本身去加载。
使用这种模型来组织类加载器之间的关系的好处是Java类随着它的类加载器一块儿具有了一种带有优先级的层次关系。例如java.lang.Object类,不管哪一个类加载器去加载该类,最终都是由启动类加载器进行加载,所以Object类在程序的各类类加载器环境中都是同一个类。不然的话,若是不使用该模型的话,若是用户自定义一个java.lang.Object类且存放在classpath中,那么系统中将会出现多个Object类,应用程序也会变得很混乱。若是咱们自定义一个rt.jar中已有类的同名Java类,会发现JVM能够正常编译,但该类永远没法被加载运行。
在rt.jar包中的java.lang.ClassLoader类中,咱们能够查看类加载实现过程的代码,具体源码以下:
Java代码
经过上面代码能够看出,双亲委派模型是经过loadClass()方法来实现的,根据代码以及代码中的注释能够很清楚地了解整个过程其实很是简单:先检查是否已经被加载过,若是没有则调用父加载器的loadClass()方法,若是父加载器为空则默认使用启动类加载器做为父加载器。若是父类加载器加载失败,则先抛出ClassNotFoundException,而后再调用本身的findClass()方法进行加载。