1、一切的基类:ClassLoader
在java中存在4种类加载器,分别是启动类加载器、扩展类加载器、系统类加载器和自定义加载器,而AppClassLoader就是其中的系统类加载器。AppClassLoader系统类加载器中包含一个parent指针指向扩展类加载器ExtClassLoader,ExtClassLoader中的parent指针指向为空,因为其上一层为启动类加载器,启动类加载器是用C++写的,因此在java中没有启动类加载器。
在我们一般代码中默认的类加载器就是系统类加载器AppClassLoader,但是无论是AppClassLoader还是ExtClassLoader,他们都继承自基类ClassLoader,注意,在ClassLoader中存在一个成员变量parent,该变量指向了自己名义上的双亲:
public abstract class ClassLoader {
//指向自己的双亲
private final java.lang.ClassLoader parent;
}
在ClassLoader中有一个非常重要的方法叫做loadClass,程序运行过程中加载类的操作就是通过这个函数来实现的,同时也是满足双亲委派机制,loadClass方法核心代码如下:
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 1、首先判断当前类加载器是否已经加载过该类
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
//2、利用父加载器进行递归加载
c = parent.loadClass(name, false);
} else {
//3、如果父加载器为空则采用启动类加载器加载,没有则返回空
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
//4、如果通过父加载器和启动类加载器都没有找到,则通过findClass寻找
long t1 = System.nanoTime();
c = findClass(name);
}
}
return c;
}
}
如上代码所示,当Java中加载一个类时会经历以下步骤:
- 首先判断当前类加载器是否已经加载了该类=>Class<?> c = findLoadedClass(name);
- 然后通过parent指针找到自己的双亲,然后递归调用parent的loadClass方法来让父类先加载,从而实现双亲委派机制。=>c = parent.loadClass(name, false);
- 如果parent为空(说明当前ClassLoader为ExtClassLoader),则通过本地方法直接调用启动类加载器来加载该类=>c = findBootstrapClassOrNull(name);
- 如果当前类加载器的父类都未能成功加载该类,则通过findClass函数自己来加载该类=>c=findClass(name)
注意,对于基类ClassLoader而言,它并没有实现findClass方法,而是将这个方法交给了自己的子类去实现,系统类加载器和扩展类加载器都实现了这个方法。
protected Class<?> findClass(String name) throws ClassNotFoundException {