- package com.test.one;
- import java.io.BufferedInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.lang.reflect.Method;
-
-
- public class AutoClassLoader extends ClassLoader {
-
-
- private static final String DEAFAULTDIR="C:/Documents and Settings/liuzhe.pt/Workspaces/MyEclipse 8.5/test/bin/";;
-
- private static String FILEPATH="";
-
-
-
-
- public Class<?> findClass(String name) throws ClassNotFoundException {
- System.out.println("----------" +
- "");
-
-
-
-
-
- byte[] b = null;
- try {
- b = loadClassData(AutoClassLoader.FormatClassName(name));
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("findclass-----over");
- return defineClass("com.test.one.tow", b, 0, b.length);
-
- }
- private byte[] loadClassData(String filepath) throws Exception {
- int n =0;
- BufferedInputStream br = new BufferedInputStream(
- new FileInputStream(
- new File(filepath)));
- ByteArrayOutputStream bos= new ByteArrayOutputStream();
- while((n=br.read())!=-1){
- bos.write(n);
- }
- br.close();
- return bos.toByteArray();
- }
-
- public Class loadClass(String name){
- System.out.println(name);
- System.out.println(name.indexOf("java."));
- if(name.indexOf("java.")<5&&name.indexOf("java.")>-1){return null;}
- Class c2=findLoadedClass("com.test.one.tow");
-
- String path=AutoClassLoader.FormatClassName(name);
- System.out.println("loadclass"+path);
-
- byte[] b = null;
- try {
- b = loadClassData(path);
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("loadclass-----over"+path);
- return defineClass("com.test.one.tow", b, 0, b.length);
- }
-
-
-
- public static String FormatClassName(String name){
-
- FILEPATH= DEAFAULTDIR+name+".class";
- return FILEPATH;
- }
-
-
-
-
- public static void main(String[] args) throws Exception {
-
- AutoClassLoader acl = new AutoClassLoader();
-
- Class c = acl.findClass("com/test/one/tow");
-
-
-
-
- System.out.println(c.getName());
- System.out.println(c.getClassLoader());
- System.out.println(c.getClassLoader().getParent());
- System.out.println(AutoClassLoader.class.getClassLoader());
- }
- }
这个源码是自定义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.io.FileNotFoundException: C:\Documents and Settings\liuzhe.pt\Workspaces\MyEclipse 8.5\test\bin\java.lang.Object.class (系统找不到指定的文件。)
- at java.io.FileInputStream.open(Native Method)
- at java.io.FileInputStream.<init>(Unknown Source)
- at com.test.one.AutoClassLoader.loadClassData(AutoClassLoader.java:40)
- at com.test.one.AutoClassLoader.loadClass(AutoClassLoader.java:61)
- at java.lang.ClassLoader.defineClass1(Native Method)
- at java.lang.ClassLoader.defineClassCond(Unknown Source)
- at java.lang.ClassLoader.defineClass(Unknown Source)
- at java.lang.ClassLoader.defineClass(Unknown Source)
- at com.test.one.AutoClassLoader.findClass(AutoClassLoader.java:34)
- at com.test.one.AutoClassLoader.main(AutoClassLoader.java:84)
- Exception in thread "main" java.lang.NullPointerException
- at com.test.one.AutoClassLoader.loadClass(AutoClassLoader.java:66)
- at java.lang.ClassLoader.defineClass1(Native Method)
- at java.lang.ClassLoader.defineClassCond(Unknown Source)
- at java.lang.ClassLoader.defineClass(Unknown Source)
- at java.lang.ClassLoader.defineClass(Unknown Source)
- at com.test.one.AutoClassLoader.findClass(AutoClassLoader.java:34)
- at com.test.one.AutoClassLoader.main(AutoClassLoader.java:84)
可以看出 调用了 AutoClassLoader的方法loadClass,然后再往下看又一个ClassLoader的defineClass1 这是一个本地方法!也就是说 defineClass1调用了loadClass的方法 ,但是由于调用方法的对象AutoClassLoader有自定义方法loadClass
所以根据多态性,所以就调用了子类自己的方法!
然而自己的方法显然找不到自己的方法
但是你可以这样写 loadClass!!
- public Class loadClass(String name){
- System.out.println(name);
- System.out.println(name.indexOf("java."));
- if(name.indexOf("java.")<5&&name.indexOf("java.")>-1){try {
-
- return super.loadClass(name);
- } catch (ClassNotFoundException e) {
-
- e.printStackTrace();
- }}
- Class c2=findLoadedClass("com.test.one.tow");
-
- String path=AutoClassLoader.FormatClassName(name);
- System.out.println("loadclass"+path);
-
- byte[] b = null;
- try {
- b = loadClassData(path);
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("loadclass-----over"+path);
- return defineClass("com.test.one.tow", b, 0, b.length);
- }
下面是最终执行的defineClass的源码
- protected final Class<?> defineClass(String name, byte[] b, int off, int len,
- ProtectionDomain protectionDomain)
- throws ClassFormatError
- {
- check();
- protectionDomain = preDefineClass(name, protectionDomain);
-
- Class c = null;
- String source = defineClassSourceLocation(protectionDomain);
-
- try {
- c = defineClass1(name, b, off, len, protectionDomain, source);
- } catch (ClassFormatError cfe) {
- c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, source);
- }
-
- postDefineClass(c, protectionDomain);
- return c;
- }
-
- }
可以看出先要交给父加载器去加载
这时根据多态性,调用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