1、Java语言系统自带有三个类加载器:
- Bootstrap ClassLoader 最顶层的加载类,主要加载核心类库,%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。另外需要注意的是可以通过启动jvm时指定-Xbootclasspath和路径来改变Bootstrap ClassLoader的加载目录。比如java -Xbootclasspath/a:path被指定的文件追加到默认的bootstrap路径中。我们可以打开我的电脑,在上面的目录下查看,看看这些jar包是不是存在于这个目录。(加载基础类。eg:int、String、float)
- Extention ClassLoader 扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。还可以加载-D java.ext.dirs选项指定的目录。
- Appclass Loader也称为SystemAppClass 加载当前应用的classpath(eclipse中的workspace)的所有类。
2、加载类的顺序
1. Bootstrap CLassloder-----根类加载器
2. Extention ClassLoader-----扩展类加载器
3. AppClassLoader-----系统类加载器
3、每个类加载器都有一个父加载器(除了Bootstrap加载器)。父加载器不是父类
URLClassLoader的源码中并没有找到getParent()方法。这个方法在ClassLoader.java中。
一个ClassLoader创建时如果没有指定parent,那么它的parent默认就是AppClassLoader。
AppClassLoader的父加载器是ExtClassLoader,而ExtClassLoader的父加载器是null(但是此时会交由Bootstrap类加载器去加载,int的加载器是null,但是是由Bootstrap类加载器加载)。
4.双亲委派机制
一个类加载器查找class和resource时,是通过“委托模式”进行的。
用序列描述一下:
1. 一个AppClassLoader查找资源时,先看看缓存是否有,缓存有从缓存中获取,否则委托给父加载器。
2. 递归,重复第1部的操作。
3. 如果ExtClassLoader也没有加载过,则由Bootstrap ClassLoader出面,它首先查找缓存,如果没有找到的话,就去找自己的规定的路径下,也就是sun.mic.boot.class下面的路径。找到就返回给子类加载器,没有找到,让子加载器自己去找。
4. Bootstrap ClassLoader如果没有查找成功,则ExtClassLoader自己在java.ext.dirs路径中去查找,查找成功就返回给子类加载器,查找不成功,再向下让子加载器找。
5. ExtClassLoader查找不成功,AppClassLoader就自己查找,在java.class.path路径下查找。找到就返回给子类加载器。如果没有找到就让子类找,如果没有子类会怎么样?抛出各种异常。
ClassLoader类中的loadClass方法定义了上述的双亲委托,在自定义ClassLoader时(自定义ClassLoader可以加载任意位置的.class文件并对.class文件中的内容进行解密后加载到jvm中),一般不用重写loadClass方法(此时自定义的ClassLoader类的父加载器是AppClassLoader),需要重写findClass()方法并且在findClass()中调用defineClass()方法(它能将class二进制内容转换成Class对象,如果不符合要求的会抛出各种异常。)
双亲委派模型的优点:
Java类伴随其类加载器具备了带有优先级的层次关系,确保了在各种加载环境的加载顺序。
保证了运行的安全性,防止不可信类扮演可信任的类。
eg:自定义一个java.lang.Object类型,此时的话也不会与bootstrap类加载器路径下的java.lang.Object类型冲突,因为会首先加载bootstrap类加载器路径下的java.lang.Object类型,如果没有双亲委托模型的话那么就出现先加载自定义类的情况,此时的话就会出现问题。