在类加载过程中的加载阶段,其任务之一是通过类的全限定名称来获取此类的二进制字节流,而虚拟机规范并没有限制二进制字节流的来源方式,因此类加载器就是用来通过指定的途径加载字节流的。
对于任意一个类来说,它的唯一性是通过类加载器和这个类本身来确定的,也就是说即便两个类加载自同一个Class文件,并且都由同一个虚拟机加载,只要加载这个类的类加载器不同,那么这两个类就必定不相等。
从Java虚拟机的角度讲,类加载器分为两种,一种是启动类加载器(BootstrapClassLoader),它是C++语言编写的,属于虚拟机的一部分;另外一种是除启动类加载器之外的任何加载器,他们是Java语言编写的,并且独立于虚拟机之外,全都继承自抽象类Java.lang.ClassLoader。
从Java开发人员的角度讲,类加载器分为三种,分别是:
●启动类加载器(BootstrapClassLoader):负责将在JAVA_HOME/lib目录下的类库,并且不能被Java程序直接引用,当我们需要委派该类加载器加载类时,使用null代替即可。
●扩展类加载器(Extension ClassLoader):负责加载JAVAHOME/lib/ext目录下的类库,它可被程序直接引用。
●应用程序类加载器(Application ClassLoader):负责加载用户类路径上(CLASSPATH)所指定的类库,它可被程序直接引用。此外,如果应用程序没有自定义过直接的类加载器,那么应用程序加载器就是默认的类加载器。
●双亲委派模型要求除了顶层的启动类加载器(Bootstrap ClassLoader)之外,其余的类加载都要有自己的父类加载器。这里的父子关系不是以继承而是以组合的方式实现的。
●双亲委派模式不是一个强制性的约束模式,而是一种推荐的类加载器模型。
当一个类加载器收到加载类的请求时,它不会自己立即尝试去加载这个类,而是委派父类加载器去加载这个类,而父类(或者说每个层级的类加载器)也是如此,直至类加载求被委派至顶层的类启动加载器,只有当父类加载器反馈自己无法加载该类时,子类才会尝试自己去加载该类。
Java类随着类加载器而带有了一种带有优先级的层次关系。例如对于Java.lang.Object类,无论采用哪种来加载器对它进行加载,加载请求最终都将委派给启动类加载器来执行,根据类唯一性的确定原则,程序都将只有一个Java.lang.Object类。如果没有采用双亲委派模型,假设用户自己在CLASSPATH下存放了Java.lang.Object类,那么系统将会有两个不同的Object类,这容易导致编码时产生混乱。