一,关系图及各自管辖范围 (不赘述)
二,查看关系
package com.jiazai;
public class Main {
public static void main(String[] args) {
ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();//默认
System.out.println(appClassLoader);
ClassLoader exClassLoader = appClassLoader.getParent();
System.out.println(exClassLoader);
ClassLoader bootstrapClassLoader = exClassLoader.getParent();
System.out.println(bootstrapClassLoader);
}
}
为什么根加载器是空?因为是C/C++写的。
三,源码:调用过程
findLoadedClass当前类加载器是否加载过这个类,当然首次加载肯定没有。
向上委托,调用parent的loadClass方法。对于appClassLoader来说,parent就是ExtClassLoader...
findClass是尝试自己加载这个类,如果说自己的管辖范围内没这个类,我没这个能力加载,那就返回调用者(向下加载)。
四,自定义类加载器
自定义类加载器需要继承java.lang.ClassLoader类,这个类有两个核心方法,一个是loadClass,这个是真正意义上双亲委派机制的实现类。是loadClass来层层委派的,而findClass就是去查找管辖范围内有没有这个类,有的话尝试加载,这个方法是一个具体加载的位置。(这是个面试题)
如果需要打破双亲委派机制,那就重写loadClass,如果是想完成自定义路径的类加载那么需要重写findClass。
示例:
public class ClassLoader_Demo {
static class CJClassLoader extends ClassLoader{
private String classPath;
public CJClassLoader(String classPath){
this.classPath = classPath;
}
private byte[] getBytes(String name) throws Exception {
name = name.replaceAll("\\.","/");
FileInputStream fileInputStream = new FileInputStream(classPath + "/" + name + ".class");
int len = fileInputStream.available();
byte[] data = new byte[len];
fileInputStream.read(data);
fileInputStream.close();
return data;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] bytes = getBytes(name);
return defineClass(name, bytes, 0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}
}
public static void main(String[] args) throws ClassNotFoundException {
CJClassLoader cjClassLoader = new CJClassLoader("D:\\新建文件夹");
Class<?> aClass = cjClassLoader.loadClass("YangGuang");
System.out.println(aClass.getClassLoader().getClass().getName());
}
}
上面这串代码自定义了一个类加载器,但是只是重写了findClass,没打破双亲委派机制(仍然会走jdk loadClass那串逻辑,可以自己debug试试)