关于Classloader的总结!loadClass的分析和加载细节的分析

Java代码   收藏代码
  1. package com.test.one;  
  2. import java.io.BufferedInputStream;  
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.File;  
  5. import java.io.FileInputStream;  
  6. import java.lang.reflect.Method;  
  7.   
  8.   
  9. public class AutoClassLoader extends ClassLoader {  
  10.   
  11.     //定义文件所在目录  
  12.     private static final String DEAFAULTDIR="C:/Documents and Settings/liuzhe.pt/Workspaces/MyEclipse 8.5/test/bin/";;  
  13.     //定义文件绝对路径  
  14.     private static String FILEPATH="";  
  15.       
  16.     /* 
  17.     * 重写ClassLoader类的findClass方法,将一个字节数组转换为 Class 类的实例 
  18.     */  
  19.     public Class<?> findClass(String name) throws ClassNotFoundException {  
  20.         System.out.println("----------" +  
  21.                 "");  
  22.          //Class c2=findLoadedClass("com.test.one.tow");  
  23. //         if(c2==null){  
  24. //          System.out.println(" ...null");  
  25. //           
  26. //         }  
  27.         byte[] b = null;  
  28.         try {  
  29.             b = loadClassData(AutoClassLoader.FormatClassName(name));  
  30.         } catch (Exception e) {  
  31.             e.printStackTrace();  
  32.         }  
  33.         System.out.println("findclass-----over");  
  34.         return defineClass("com.test.one.tow", b, 0, b.length);  
  35.   
  36.     }  
  37.     private byte[] loadClassData(String filepath) throws Exception {  
  38.         int n =0;  
  39.         BufferedInputStream br = new BufferedInputStream(  
  40.                         new FileInputStream(  
  41.                     new File(filepath)));  
  42.         ByteArrayOutputStream bos= new ByteArrayOutputStream();  
  43.             while((n=br.read())!=-1){  
  44.                 bos.write(n);  
  45.             }  
  46.             br.close();  
  47.         return bos.toByteArray();  
  48.     }  
  49.   //  @Override  
  50.     public Class loadClass(String name){  
  51.         System.out.println(name);//输出要加载的类!!!  
  52.          System.out.println(name.indexOf("java."));  
  53.          if(name.indexOf("java.")<5&&name.indexOf("java.")>-1){return null;}  
  54.          Class c2=findLoadedClass("com.test.one.tow");  
  55.           
  56.          String path=AutoClassLoader.FormatClassName(name);  
  57.          System.out.println("loadclass"+path);  
  58.         //   
  59.         byte[] b = null;  
  60.         try {  
  61.             b = loadClassData(path);  
  62.         } catch (Exception e) {  
  63.             e.printStackTrace();  
  64.         }  
  65.         System.out.println("loadclass-----over"+path);  
  66.         return defineClass("com.test.one.tow", b, 0, b.length);  
  67.     }  
  68.     /* 
  69.     * 格式化文件所对应的路径 
  70.     */  
  71.     public static String FormatClassName(String name){  
  72.           
  73.         FILEPATH= DEAFAULTDIR+name+".class";  
  74.         return FILEPATH;  
  75.     }  
  76.           
  77.     /* 
  78.     * main方法测试 
  79.     */  
  80.     public static void main(String[] args) throws Exception {  
  81.           
  82.         AutoClassLoader acl = new AutoClassLoader();  
  83.         //stem.out.println("-----2-----");  
  84.         Class c = acl.findClass("com/test/one/tow");  
  85.          
  86.         //Object obj = c.newInstance();  
  87.         //Method m = c.getMethod("getName",new Class[]{String.class ,int.class});  
  88.         //m.invoke(obj,"你好",123);  
  89.         System.out.println(c.getName());  
  90.         System.out.println(c.getClassLoader());  
  91.         System.out.println(c.getClassLoader().getParent());  
  92.         System.out.println(AutoClassLoader.class.getClassLoader());  
  93.     }  
  94. }  

这个源码是自定义Classloader的一个类
他定义了loadData()loadClass()findClass()
但如果你运行这个代码的话你会发现 一直报错!他是用自定义的ClassLoader加载
com.test.one.tow(一个简单的类)
说找不到 java.lang.object这个类
当然是在你指定的路径下找不到了!@
怎么出来个 java.lang.object
不知道还记得 加载类的话 他会把所有的父类都要加载一遍  直到java.lang.object
这个实现的方法是在Classloader的loadClass中实现的!
(loadClass是由defineClass1(Native Method)调用的!)
(如果你给tow定义一个父类 你就会发现输出中有加载父类的代码)
你运行了findClass  为什么会运行loadClass呢
因为你在defineClass的时候  他会自动去加载父类的class文件 这些都是Native方法
在Classloader中可以看见!其中会调用loadClass去调用
其中还会调用loadClass去加载
看下报的错误
Java代码   收藏代码
  1. java.io.FileNotFoundException: C:\Documents and Settings\liuzhe.pt\Workspaces\MyEclipse 8.5\test\bin\java.lang.Object.class (系统找不到指定的文件。)  
  2.     at java.io.FileInputStream.open(Native Method)  
  3.     at java.io.FileInputStream.<init>(Unknown Source)  
  4.     at com.test.one.AutoClassLoader.loadClassData(AutoClassLoader.java:40)  
  5.     at com.test.one.AutoClassLoader.loadClass(AutoClassLoader.java:61)  
  6.     at java.lang.ClassLoader.defineClass1(Native Method)  
  7.     at java.lang.ClassLoader.defineClassCond(Unknown Source)  
  8.     at java.lang.ClassLoader.defineClass(Unknown Source)  
  9.     at java.lang.ClassLoader.defineClass(Unknown Source)  
  10.     at com.test.one.AutoClassLoader.findClass(AutoClassLoader.java:34)  
  11.     at com.test.one.AutoClassLoader.main(AutoClassLoader.java:84)  
  12. Exception in thread "main" java.lang.NullPointerException  
  13.     at com.test.one.AutoClassLoader.loadClass(AutoClassLoader.java:66)  
  14.     at java.lang.ClassLoader.defineClass1(Native Method)  
  15.     at java.lang.ClassLoader.defineClassCond(Unknown Source)  
  16.     at java.lang.ClassLoader.defineClass(Unknown Source)  
  17.     at java.lang.ClassLoader.defineClass(Unknown Source)  
  18.     at com.test.one.AutoClassLoader.findClass(AutoClassLoader.java:34)  
  19.     at com.test.one.AutoClassLoader.main(AutoClassLoader.java:84)  

可以看出 调用了 AutoClassLoader的方法loadClass,然后再往下看又一个ClassLoader的defineClass1  这是一个本地方法!也就是说 defineClass1调用了loadClass的方法 ,但是由于调用方法的对象AutoClassLoader有自定义方法loadClass
所以根据多态性,所以就调用了子类自己的方法!
然而自己的方法显然找不到自己的方法
但是你可以这样写 loadClass!!
Java代码   收藏代码
  1.  public Class loadClass(String name){  
  2.     System.out.println(name);  
  3.      System.out.println(name.indexOf("java."));  
  4.      if(name.indexOf("java.")<5&&name.indexOf("java.")>-1){try {  
  5. //如果是java.开头的交给父类的方法获得Class实例!这样就OK   
  6.     return super.loadClass(name);  
  7. catch (ClassNotFoundException e) {  
  8.     // TODO Auto-generated catch block  
  9.     e.printStackTrace();  
  10. }}  
  11.  Class c2=findLoadedClass("com.test.one.tow");  
  12.   
  13.  String path=AutoClassLoader.FormatClassName(name);  
  14.  System.out.println("loadclass"+path);  
  15. //   
  16. byte[] b = null;  
  17. try {  
  18.     b = loadClassData(path);  
  19. catch (Exception e) {  
  20.     e.printStackTrace();  
  21. }  
  22. System.out.println("loadclass-----over"+path);  
  23. return defineClass("com.test.one.tow", b, 0, b.length);  
  24.   }  

下面是最终执行的defineClass的源码
Java代码   收藏代码
  1. protected final Class<?> defineClass(String name, byte[] b, int off, int len,  
  2.                  ProtectionDomain protectionDomain)  
  3. throws ClassFormatError  
  4.    {  
  5. check();  
  6. protectionDomain = preDefineClass(name, protectionDomain);  
  7.   
  8. Class c = null;  
  9.        String source = defineClassSourceLocation(protectionDomain);  
  10.   
  11. try {  
  12.     c = defineClass1(name, b, off, len, protectionDomain, source);//上面报错的地方  
  13. catch (ClassFormatError cfe) {  
  14.     c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, source);  
  15. }  
  16.   
  17. postDefineClass(c, protectionDomain);  
  18. return c;  
  19.    }  
  20.   
  21.    }  

可以看出先要交给父加载器去加载
这时根据多态性,调用loadClass时会使用重写的方法
所以这时加载父类,name成为了java。lang。object
在目录下当然找不到了!!
所以自定义Classloader的时候 不要重写loadClass

大体流程是这样的e

用户自定义findClass
|
|
defineClass
|
|
defineClass1(Native method)
|
|
加载父类

|------>调用loadClass加载父类(多态性)
|
----loadClass(用户自定义)(所以如果自定义这个类要把系统类交给                  --------------Classloader处理---交给上层的classLoader处理)
|
|
找不到object类
|
|
报错


重写findClass就可以!以免因为加载父类造成异常
另外推荐关于这个的文章
http://tech.sina.com.cn/s/2009-09-02/00351051784.shtml
http://www.cnblogs.com/leo-cnblogs/
或者去我的DBback下载
http://www.dbank.com/download.action?t=40&k=NDc4NjI1MzU=&pcode=LCwxMTI5OTgxLDExMjk5ODE=&rnd=4
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值