类加载器

  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 }

 

posted @ 2013-12-17 21:35  风诺  阅读(576)  评论(0)    收藏  举报