
所以默认的都是将自定义的类加载器挂载到系统类加载器的最低端AppClassLoader,这个也是很合理的。
自定义的类加载器必须继承抽象类ClassLoader然后重写findClass方法,其实他内部还有一个loadClass方法和defineClass方法,这两个方法的作用是:
loadClass方法的源代码:
public Class
loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}再来看一下loadClass(name,false)方法的源代码:
protected Class
loadClass(String name, boolean resolve)throws ClassNotFoundException{
//加上锁,同步处理,因为可能是多线程在加载类
synchronized (getClassLoadingLock(name)) {
//检查,是否该类已经加载过了,如果加载过了,就不加载了
Class c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
//如果自定义的类加载器的parent不为null,就调用parent的loadClass进行加载类
if (parent != null) {
c = parent.loadClass(name, false);
} else {
//如果自定义的类加载器的parent为null,就调用findBootstrapClass方法查找类,就是Bootstrap类加载器
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
//如果parent加载类失败,就调用自己的findClass方法进行类加载
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}在loadClass代码中也可以看到类加载机制的原理,这里还有这个方法findBootstrapClassOrNull,看一下源代码:
private Class findBootstrapClassOrNull(String name)
{
if (!checkName(name)) return null;
return findBootstrapClass(name);
}
就是检查一下name是否是否正确,然后调用findBootstrapClass方法,但是findBootstrapClass方法是个native本地方法,看不到源代码了,但是可以猜测是用Bootstrap类加载器进行加载类的,这个方法我们也不能重写,因为如果重写了这个方法的话,就会破坏这种委托机制,我们还要自己写一个委托机制,很是蛋疼的。
defineClass这个方法很简单就是将class文件的字节数组编程一个class对象,这个方法肯定不能重写,内部实现是在C/C++代码中实现的
findClass这个方法就是根据name来查找到class文件,在loadClass方法中用到,所以我们只能重写这个方法了,只要在这个方法中找到class文件,再将它用defineClass方法返回一个Class对象即可。
这三个方法的执行流程是:每个类加载器:loadClass->findClass->defineClass
前期的知识了解后现在就来实现了
首先来看一下需要加载的一个类:ClassLoaderAttachment.java:
package com.loadclass.demo;
import java.util.Date;
/**
* 加载类
* @author Administrator
*/
public class ClassLoaderAttachment extends Date{
private static final long serialVersionUID = 8627644427315706176L;
//打印数据
@Override
public String toString(){
return "Hello ClassLoader!";
}
}
这个类中输出一段话即可:编译成ClassLoaderAttachment.class
再来看一下自定义的MyClassLoader.java:
package com.loadclass.demo;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 自定义的类加载器
* @author Administrator
*/
public class MyClassLoader extends ClassLoader{
//需要加载类.class文件的目录
private String classDir;
//无参的构造方法,用于class.newInstance()构造对象使用
public MyClassLoader(){
}
public MyClassLoader(String classDir){
this.classDir = classDir;
}
@SuppressWarnings("deprecation")
@Override
protected Class
findClass(String name) thro