类加载器可以看下我的收藏:
https://www.cnblogs.com/dongguacai/p/5879931.html
现在准备一个字节码文件:
自定义加载器:
1 package com.xzlf.test; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.FileInputStream; 5 import java.io.IOException; 6 import java.io.InputStream; 7 8 /** 9 * 自定义类加载器 10 * 11 * @author xzlf 12 * 13 */ 14 public class MyClassLoader extends ClassLoader { 15 // 类加载器查找的根目录 16 private String rootDir; 17 18 public MyClassLoader(String rootDir) { 19 super(); 20 this.rootDir = rootDir; 21 } 22 23 @Override 24 protected Class<?> findClass(String name) throws ClassNotFoundException { 25 // 查看 c 是否已经被加载 26 Class<?> c = findLoadedClass(name); 27 if(c != null) { 28 // 已经加载直接返回 29 return c; 30 }else { 31 // 没有被加载,先委派给父类加载器, 最终会委派到引导类加载器 32 ClassLoader parent = this.getParent(); 33 try { 34 c = parent.loadClass(name); 35 } catch (ClassNotFoundException e) { 36 //e.printStackTrace(); 37 } 38 // 如果父类加载器已加载则直接返回,如果没有加载则使用自定加载器加载类的字节码文件 39 if(c != null) { 40 return c; 41 }else { 42 // 获取字节码文件 43 byte[] classDatas = getClassData(name); 44 if(classDatas == null) { 45 throw new ClassNotFoundException(); 46 }else { 47 //Converts an array of bytes into an instance of class 48 c = defineClass(name, classDatas, 0, classDatas.length); 49 } 50 } 51 } 52 return c; 53 } 54 55 // 获取字节码文件 56 private byte[] getClassData(String name) { 57 //com.test.A --> f:/mycode/ com/test/A.class 58 String path = rootDir + "/" + name.replace('.', '/') + ".class"; 59 60 // IO 操作 返回字节码 61 InputStream is = null; 62 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 63 try { 64 is = new FileInputStream(path); 65 byte[] flush = new byte[1024]; 66 int len; 67 while((len = is.read(flush)) != -1) { 68 bos.write(flush, 0, len); 69 } 70 return bos.toByteArray(); 71 } catch (Exception e) { 72 e.printStackTrace(); 73 }finally { 74 if(bos != null) { 75 try { 76 bos.close(); 77 } catch (IOException e) { 78 e.printStackTrace(); 79 } 80 } 81 if(is != null) { 82 try { 83 is.close(); 84 } catch (IOException e) { 85 e.printStackTrace(); 86 } 87 } 88 } 89 return null; 90 } 91 }
测试代码:
1 package com.xzlf.test; 2 3 public class TestClassLoader { 4 public static void main(String[] args) throws Exception { 5 MyClassLoader loader1 = new MyClassLoader("f:/mycode"); 6 MyClassLoader loader2 = new MyClassLoader("f:/mycode"); 7 8 Class<?> c1 = loader1.loadClass("com.test.Welcome"); 9 Class<?> c2 = loader1.loadClass("com.test.Welcome"); 10 Class<?> c3 = loader2.loadClass("com.test.Welcome"); 11 12 Class<?> c4 = loader2.loadClass("java.lang.String"); 13 Class<?> c5 = loader2.loadClass("com.xzlf.test.MyClassLoader"); 14 15 // 自定义加载器 16 System.out.println("c1-->" + c1.hashCode() + "-->" + c1.getClassLoader()); 17 System.out.println("c2-->" + c2.hashCode() + "-->" + c2.getClassLoader()); 18 19 // 同一个类,被不同的加载器加载,JVM认为也是不相同的类 20 System.out.println("c3-->" + c3.hashCode() + "-->" + c3.getClassLoader()); 21 22 // 引导加载器 23 System.out.println("c4-->" + c4.hashCode() + "-->" + c4.getClassLoader()); 24 25 // 应用加载器 26 System.out.println("c5-->" + c5.hashCode() + "-->" + c5.getClassLoader()); 27 } 28 }
运行测试: