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


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="";

/*
* 重写ClassLoader类的findClass方法,将一个字节数组转换为 Class 类的实例
*/
public Class<?> findClass(String name) throws ClassNotFoundException {
System.out.println("----------" +
"");
//Class c2=findLoadedClass("com.test.one.tow");
// if(c2==null){
// System.out.println(" ...null");
//
// }
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();
}
// @Override
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;
}

/*
* main方法测试
*/
public static void main(String[] args) throws Exception {

AutoClassLoader acl = new AutoClassLoader();
//stem.out.println("-----2-----");
Class c = acl.findClass("com/test/one/tow");

//Object obj = c.newInstance();
//Method m = c.getMethod("getName",new Class[]{String.class ,int.class});
//m.invoke(obj,"你好",123);
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 {
//如果是java.开头的交给父类的方法获得Class实例!这样就OK
return super.loadClass(name);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
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
[color=red]
用户自定义findClass
|
|
defineClass
|
|
defineClass1(Native method)
|
|
加载父类
|
|------>调用loadClass加载父类(多态性)
|
----loadClass(用户自定义)(所以如果自定义这个类要把系统类交给 --------------Classloader处理---交给上层的classLoader处理)
|
|
找不到object类
|
|
报错
[/color]

重写findClass就可以!以免因为加载父类造成异常
另外推荐关于这个的文章
[url]http://tech.sina.com.cn/s/2009-09-02/00351051784.shtml[/url]
[url]http://www.cnblogs.com/leo-cnblogs/[/url]
或者去我的DBback下载
[url]http://www.dbank.com/download.action?t=40&k=NDc4NjI1MzU=&pcode=LCwxMTI5OTgxLDExMjk5ODE=&rnd=4[/url]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值