注意:类加载器之间的父子关系并不是类继承上的父子关系,而是实例之间的父子关系。
public class ClassloaderPropTest {public static void main(String[] args) throws IOException {
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println("系统类加载器:" + systemClassLoader);
/*
获取系统类加载器的加载路径——通常由CLASSPATH环境变量指定,如果操作系统没有指定
CLASSPATH环境变量,则默认以当前路径作为系统类加载器的加载路径
*/
Enumeration<URL> eml = systemClassLoader.getResources("");
while (eml.hasMoreElements()) {
System.out.println(eml.nextElement());
}
//获取系统类加载器的父类加载器,得到扩展类加载器
ClassLoader extensionLoader = systemClassLoader.getParent();
System.out.println("系统类的父加载器是扩展类加载器:" + extensionLoader);
System.out.println("扩展类加载器的加载路径:" + System.getProperty("java.ext.dirs"));
System.out.println("扩展类加载器的parant:" + extensionLoader.getParent());
}
}
//输出结果
//系统类加载器:sun.misc.Launcher$AppClassLoader@18b4aac2
//file:/C:/ProjectTest/FengKuang/out/production/FengKuang/
//系统类的父加载器是扩展类加载器:sun.misc.Launcher$ExtClassLoader@1540e19d
//扩展类加载器的加载路径:C:\SorftwareInstall\java\jdk\jre\lib\ext;C:\WINDOWS\Sun\Java\lib\ext
//扩展类加载器的parant:null
从输出中验证了:系统类加载器的父加载器是扩展类加载器。但输出中扩展类加载器的父加载器是null,这是因为父加载器不是java实现的,是C++实现的,所以获取不到。但扩展类加载器的父加载器是根加载器。
1.2、类加载流程图图中红色部分,可以是我们自定义实现的类加载器来进行加载。
五、创建并使用自定义类加载器 1、自定义类加载分析除了根类加载器,所有类加载器都是ClassLoader的子类。所以我们可以通过继承ClassLoader来实现自己的类加载器。
ClassLoader类有两个关键的方法:
protected Class loadClass(String name, boolean resolve):name为类名,resove如果为true,在加载时解析该类。
protected Class findClass(String name) :根据指定类名来查找类。
所以,如果要实现自定义类,可以重写这两个方法来实现。但推荐重写findClass方法,而不是重写loadClass方法,因为loadClass方法内部回调用findClass方法。
我们来看一下loadClass的源码
protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
//第一步,先从缓存里查看是否已经加载
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
//第二步,判断父加载器是否为null
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) {
//第三步,如果前面都没有找到,就会调用findClass方法
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
loadClass加载方法流程:
判断此类是否已经加载;
如果父加载器不为null,则使用父加载器进行加载;反之,使用跟加载器进行加载;
如果前面都没加载成功,则使用findClass方法进行加载。
所以,为了不影响类的加载过程,我们重写findClass方法即可简单方便的实现自定义类加载。
2、实现自定义类加载器