操作流程都在代码注释中:
/** * 自定义文件系统类加载器 ---->使用自定义类加载器加载 某一目录下的字节码 * @author * 将d:/myjava/com/zm/HelloWorld.class 通过自定义类加载器加载 * * 1 extends ClassLoader 重写findClass(String name) * 2 findClass(String name)内先去findLoadedClass(name)中找 没找到在去parent.loadClass(name)找,在没找到则用自己的代码 * 写流获取目标文件的byte[] * 3 根据 c = defineClass(name, classData, 0,classData.length);得到Class对象并返回即可 * */ public class FileSystemClassLoader extends ClassLoader { // d:/myjava/ private String rootDir; public FileSystemClassLoader(String rootDir){ this.rootDir = rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { // 先去加载器里面看看已经加载到的类中是否有这个类 Class<?> c = findLoadedClass(name); // loader.loadClass("com.zm.HelloWorld"); //应该要先查询有没有加载过这个类。如果已经加载,则直接返回加载好的类。如果没有,则加载新的类。 if(c!=null){ return c; }else{ ClassLoader parent = this.getParent(); try { c = parent.loadClass(name); //委派给父类加载 调用JVM委托机制来加载,如果一层层上抛都没有加载到com.zm.HelloWorld的话 则走到46行 调用自己的类加载 } catch (Exception e) { // e.printStackTrace(); } if(c!=null){ return c; }else{// byte[] classData = getClassData(name); if(classData==null){ throw new ClassNotFoundException(); }else{ // 将字节码处理成 Class实例返回 c = defineClass(name, classData, 0,classData.length); } } } return c; } // 读取流 将读到的流处理成字节码数组返回 private byte[] getClassData(String classname){ //com.zm.HelloWorld d:/myjava/ com/zm/HelloWorld.class String path = rootDir +"/"+ classname.replace('.', '/')+".class"; // IOUtils,可以使用它将流中的数据转成字节数组 InputStream is = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try{ is = new FileInputStream(path); byte[] buffer = new byte[1024]; int temp=0; while((temp=is.read(buffer))!=-1){ baos.write(buffer, 0, temp); } return baos.toByteArray(); }catch(Exception e){ e.printStackTrace(); return null; }finally{ try { if(is!=null){ is.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(baos!=null){ baos.close(); } } catch (IOException e) { e.printStackTrace(); } } } } 2 public class Demo03 { public static void main(String[] args) throws Exception{ FileSystemClassLoader loader = new FileSystemClassLoader("d:/myjava"); FileSystemClassLoader loader2 = new FileSystemClassLoader("d:/myjava"); Class<?> c = loader.loadClass("com.zm.HelloWorld"); Class<?> c2 = loader.loadClass("com.zm.HelloWorldd"); Class<?> c3 = loader2.loadClass("com.zm.HelloWorld"); Class<?> c4 = loader2.loadClass("java.lang.String"); Class<?> c5 = loader2.loadClass("com.zm.HelloWorld"); System.out.println(c.hashCode()); System.out.println(c2.hashCode()); System.out.println(c3.hashCode()); //同一个类,被不同的加载器加载,JVM认为也是不相同的类 System.out.println(c4.hashCode()); System.out.println(c4.getClassLoader()); //引导类加载器 System.out.println(c3.getClassLoader()); //自定义的类加载器 System.out.println(c5.getClassLoader()); //系统默认的类加载器 } }