重点:理解双亲委派模型 ClassLoader类默认的loadClass方法已经帮我们写好了,我们无需去写
一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类, 而是把这个请求委派给父类加载器完成。 每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时 (即ClassNotFoundException),子加载器才会尝试自己去加载自定义类加载器实现过程 1、继承应用加载器(APP ClassLoader) 2、重写findclass方法 3、加载指定路径下的class文件 4、将class文件转成数组 5、调用defineClass方法将数组转成Class对象
package pers.yezi.test; import java.io.*; public class MyClassLoader extends ClassLoader { private String dir; public MyClassLoader(String dir) { this.dir = dir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] bytes = null; //查找指定位置的class文件 File file = findClassFile(name); //将class文件转化为数组 try { bytes = getArrays(file); } catch (IOException e) { e.printStackTrace(); } //将数组转为Class对象 if (bytes != null) { //返回Class对象 return defineClass(name, bytes, 0, bytes.length); } return null; } //将class文件转为数组 private byte[] getArrays(File file) throws IOException { InputStream inputStream = new FileInputStream(file); ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); int len; byte[] bytes = new byte[8 * 1024]; while ((len = inputStream.read(bytes)) != -1) { arrayOutputStream.write(bytes, 0, len); } return arrayOutputStream.toByteArray(); } //获取class文件 private File findClassFile(String name) { String path; //格式化路径,判断路径末尾是否为/,将文件名中的.转为/ if (!this.dir.endsWith("/")) { this.dir = this.dir.concat("/"); } path = this.dir.concat(name.replace(".", "/").concat(".class")); //获取文件 File file = new File(path); //返回文件 return file; } public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { MyClassLoader loader = new MyClassLoader("F:"); //加载类的名字要与源文件添加的包名一致 Class<?> aClass = loader.loadClass("pers.yezi.test.test"); System.out.println(aClass.newInstance().toString()); } }注意:如果使用junit单元测试,需要在类中提供无参构造方法,否则会报错test class should have exactly one public zero-argument constructor
参考文档 1、https://www.cnblogs.com/wxd0108/p/6681618.html 2、https://blog.csdn.net/FloatDreamed/article/details/92705069
