1 package com.itheima.classloader;
2
3 import java.io.BufferedInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.FileInputStream;
6 import java.io.IOException;
7 import java.lang.reflect.Constructor;
8
9 public class MyClassLoader extends ClassLoader {
10 public static void main(String[] args) throws Exception {
11 //通过自定义类加载器加载类,(任意指定目录和名称)
12 Class<?> clazz = new MyClassLoader("ClassLoaderLib").loadClass("Person");
13 //获取构造方法
14 Constructor<?> con = clazz.getConstructor(String.class, int.class);
15 //创建对象,成功加载则执行静态代码块中的打印语句打印信息
16 Object obj = con.newInstance("张三",15);
17 //打印该类的类加载器
18 System.out.println(obj.getClass().getClassLoader());
19 }
20
21 //classDir记录类所在目录
22 private String classDir;
23
24 /**
25 * 复写findClass方法
26 * 因为自定义的类加载器MyClassLoader继承了ClassLoader类,继承了其所有方法
27 * 通过loadClass(String name)方法加载类的时候:
28 * 1、会检查该类是否已经加载,如果没有,会依次委托MyClassLoader的父类、父类的父类
29 * 等类加载器依次尝试加载,都失败则执行findClass(String name)试图获取待加载的类的Class对象
30 * 2、而ClassLoader中findClass(String name)方法直接抛出ClassNotFoundException(name)
31 * 3、因此复写findClass(String name)方法就是以自定义的方式获取类(在父类都无法加载的情况)
32 * 4、通过将某个.class文件读入一个byte类型的数组中,然后通过defineClass方法
33 * 获取该字节码文件(Class对象)并返回
34 * 5、因此,当1中的情况出现时,本类即可通过findClass(String name)获取Class对象给
35 * loadClass(String name)方法,使其返回同一个Class对象
36 *
37 * 本类主函数内:
38 * new MyClassLoader("ClassLoaderLib").loadClass("Person");
39 * new MyClassLoader("ClassLoaderLib").findClass("Person");
40 *
41 * 因为protected权限修饰符,其他类调用本类加载某个类只能用loadClass方法
42 *
43 */
44 @Override
45 protected Class<?> findClass(String name) throws ClassNotFoundException {
46 //获取字节码文件的完整路径
47 String classPath = classDir + "\\" + name + ".class";
48 //定义Class对象引用
49 Class<?> clazz = null;
50 //设置字节输入流引用
51 BufferedInputStream bos = null;
52 //定义字节数组输出流引用
53 ByteArrayOutputStream baos = null;
54 try {
55 //建立字节输入流
56 bos = new BufferedInputStream(new FileInputStream(classPath));
57 //定义缓冲数组buf,len记录结束标记
58 byte[] buf = new byte[1024];
59 int len = -1;
60 //新建字节数组输出流(内部维护了一个字节数组)
61 baos = new ByteArrayOutputStream();
62 //循环读取,写入baos中的字节数组
63 while ((len = bos.read(buf)) != -1) {
64 baos.write(buf, 0, len);
65 }
66 //获取baos中的字节数组
67 byte[] bytes = baos.toByteArray();
68 //将该字节数组变成字节码文件
69 clazz = defineClass(null, bytes, 0, bytes.length);
70 } catch (IOException e) {
71 // TODO Auto-generated catch block
72 e.printStackTrace();
73 //关闭流
74 } finally {
75 try {
76 if (bos != null) {
77 bos.close();
78 }
79 } catch (IOException e) {
80 // TODO Auto-generated catch block
81 e.printStackTrace();
82 }
83 try {
84 if (baos != null) {
85 baos.close();
86 }
87 } catch (IOException e) {
88 // TODO Auto-generated catch block
89 e.printStackTrace();
90 }
91 }
92 //加载过程中失败则终止程序,否则返回该类
93 if (clazz == null) {
94 throw new RuntimeException("类不存在");
95 } else {
96 return clazz;
97 }
98
99 }
100 /**
101 * 构造函数传递待加载类所在的目录
102 * @param classDir 待加载的类所在的目录
103 */
104 public MyClassLoader(String classDir) {
105 this.classDir = classDir;
106 }
107
108 }