Java是运行在Java虚拟机(JVM)上
,我们在IDE上编写完的Java源代码被编译器编译成.class的字节码文件,然后由我们得到的CLassLoader负责将这些class文件加载到JVM中去执行;
JVM中提供了三层的ClassLoader(不包括自定义类加载器):
- Bootstrap classLoader:启动类加载器,“主要负责加载核心的类库,将存放在\lib目录中等路径下被虚拟机识别的问价加载到虚拟机中
- Extension ClassLoader:扩展类加载器,负责加载<JAVA_HOME>\lib\ext目录下的jar
- Application ClassLoader:应用程序加载器,主要负责加载应用程序的主函数类
双亲委派机制
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
// ----------
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
return c;
}
这段代码就是解释了我们的双亲委托机制,即当要加载一个类时,当前类加载器先看看自己的缓存里面有没有这个类,如果没有,它不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是将这个请求交给他们的父类去完成,因此所有的加载请求最终都传到了我们顶层的启动类加载器中,只有当父类加载器无法完成这个加载请求时,子类才会尝试去加载这个类,如果子类也无法加载,那么将会抛出 ClassNotFoundException异常;
我们用流程图来理解这句话吧
这就是双亲加载机制代码的流程图,我们就可以理解,当一个请求过来时,就是先检查,如果没有再给父类,一直这样下去,如果父类不行,再回到子类,如果子类不行,就抛出异常了;
双亲委托机制的优点
如果有人想替换系统级别的类,比如 String.java,来篡改他的实现,但是在这种机制下,这些类都已经被Bootstrap ClassLoader加载过了,就不会再去加载了,这种Java类随着它的加载器一起具备了一种带有优先级的层次关系,就防止了危险代码的植入了,且这样也不会因为加载了多个名字相同但是功能不同的类而呆滞程序变得混乱,总的来说,就是保证了Java程序的稳定性