在上一篇博客中写到双亲委派机制.传送门
了解完双亲委派机制那么对JVM类加载器原理有一定的了解,那么书写定义类加载加载器就不会太难了.主要是重写ClassLoader中findClass方法
这个方法主要是根据包名查找class文件
package com.bonc.jvm;
import java.io.FileInputStream;
import java.lang.reflect.Method;
/**
* @Classname MyClassLoadTEst
* @Description TODO
* @Date 2020/6/14 16:31
* @Created by sz
*/
public class MyClassLoadTest {
static class MyClassLoad extends ClassLoader{
private String classPath;
public MyClassLoad(String classPath){
this.classPath=classPath;
}
private byte[] loadByte(String name) throws Exception {
name = name.replaceAll("\\.", "/");
FileInputStream fis = new FileInputStream(classPath + "/" + name
+ ".class");
int len = fis.available();
byte[] data = new byte[len];
fis.read(data);
fis.close();
return data;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] data = loadByte(name);
//defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节 数组。
return defineClass(name, data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}
}
public static void main(String[] args) throws Exception {
MyClassLoad classLoader = new MyClassLoad("D:/tmp");
Class clazz = classLoader.loadClass("com.bonc.jvm.User1");
Object obj = clazz.newInstance();
Method method = clazz.getDeclaredMethod("print", null);
method.invoke(obj,null);
System.out.println(clazz.getClassLoader().getClass().getName());
}
}
package com.bonc.jvm;
import java.io.PrintStream;
public class User1
{
private int age;
public void print()
{
System.out.println("自定义ClassLoad");
}
}
运行结果:
执行前提:当前classpath没有那个class文件
那么加在自定义加载器之后,整个类加载机制就更新为
注意:MyClassLoad AppClassLoader ExtClassLoader 之间都不存在继承关系.只是MyClassLoad 的parent属性是AppClassLoader 并且AppClassLoader 的parent属性是ExtClassLoader