介绍双亲委派机制前,需要先介绍下Java自带的三个类加载器:
1、BootstrapClassLoader:是ExtensionClassLoader的父类加载器(这儿的父类不是继承关系,而是ExtClassLoader的一个Parent属性对应的是BootstrapClassLoader而已),它的默认加载类路径是%JAVA_HOME%的lib下的Jar包和Class文件
2、ExtensionClassLoader: 是ApplicationClassLoader的父类加载器,它的默认加载类路径是%JAVA_HOME%的lib/ext下的Jar包和Class文件
3、ApplicationClassLoader: 是自定义类加载器的父类加载器,它的加载类路径是 classpath下的文件(即我们写的class文件)
双亲委派机制 原理:
可以先看一段源码:
classLoader.loadClass("java.util.List");
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
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.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
PerfCounter.getParentDelegationTime().addTime(t1 - t0);
PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
这段代码就是双亲委派机制的核心代码,
举例:自己写Demo.class
根据代码来看,顺序就是,会先根据 className 去 ApplicationClassLoader的缓存中去寻找是否已加载Demo.class文件,如果不为空就直接跳过加载逻辑,如果为空就去父类加载器 ExtensionClassLoader的缓存中找是否已加载,同样的,如果都没有找到就去BootStrapClassLoader去找,如果都找不到,证明没有加载,所以就需要去加载,加载的过程也是,会先是 BootStrapClassLoader去默认的路径中找Demo.class,如果找到就加载,没有找到就往下ExtensionClassLoader中的默认路径去找,同理,最后会到ApplicationClassLoader中去找,找到了,就会加载Demo.class,并放入缓存中
如下图:
双亲委派机制的作用:
从原理可以看出,这个机制其实就是为了保护Java的底层不会被应用程序所覆盖
类的加载过程:
加载 -> 连接 -> 初始化
加载:把Java的字节码数据加载到JVM内存中,并映射成JVM认可的数据结构
连接:分为三个小的阶段:
1、验证:检查加载的字节信息是否符合JVM的规范
2、准备:创建类或接口的静态变量、并赋初始值 即类似创建对象中的 半初始化状态
3、解析:把符号引用转为直接引用
初始化: