Java高新技术第一篇:类加载器详解(二)

2014-11-24 07:20:30 · 作者: · 浏览: 1

\

所以默认的都是将自定义的类加载器挂载到系统类加载器的最低端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