实现自己的类加载器

      有时候,根据自己项目的需求,需要重新实现属于自己的类加载器,以满足项目的灵活性和扩展性,下面我们就来实现自己的类加载器.
   实现自己的类加载器必须首先继承一个父类加载器.

   编写一个类加载器会涉及到以下几个方法:
     1. findClass(String name)   根据类的路径查找类,必须重写的方法

     2.defineClass(String name, byte[] b, int off, int len)   由父类实现,直接调用
     3.loadClass(String name)首先调用父类的findClass方法找,找不到则调用自身重写的findClass方法找,也不需要我们实现.loadClass(String name)默认会调用loadClass(name,false)方法,表示只加载,不发生连接操作.JDK的ClassLoader类的loadClass(String name,boolean resolve)方法的实现如下:

 

 protected synchronized Class<?> loadClass(String name, boolean resolve)  throws ClassNotFoundException
    {
	// 如果该类以前被调用,则直接调用
	Class c = findLoadedClass(name);
	if (c == null) {
	    try {
		if (parent != null) {
		    c = parent.loadClass(name, false);
		} else {
		    c = findBootstrapClass0(name);
		}
	    } catch (ClassNotFoundException e) {
	        // 自己实现的findClass方法被调用
	        c = findClass(name);
	    }
	}
	if (resolve) { //进行类的连接,与其他类发生联系
	    resolveClass(c);
	}
	return c;
    }

   可以看出ClassLoader采用了模版模式,在父类加载器加载不到想要的类时,采用自己实现的方法.

 

   自己写的类加载器及测试代码如下:

 

 

public class MyClassLoader extends ClassLoader {
	private String path = "c:/bin/";

	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		String namePath = name.replace(".", "/");
		String classPath = path + namePath + ".class";
		InputStream is = null;
		ByteArrayOutputStream os = null;
		try {
			is = new FileInputStream(new File(classPath));
			os = new ByteArrayOutputStream();
			int b = 0;
			while ((b = is.read()) != -1) {
				os.write(b);
			}
			byte[] bytes = os.toByteArray();
			os.flush();
			return defineClass(name, bytes, 0, bytes.length);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				if(os!=null)
					os.close();
				if(is!=null)
					is.close();
			} catch (IOException e1) {
				os=null;
			   is = null;
			}		
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public static void main(String[] args) {
		MyClassLoader myLoader = new MyClassLoader();
		try {
		         Class myClass = myLoader.loadClass("com.ldh.loader.HelloWorld");
		         Object obj = myClass.newInstance();
		         Method method = myClass.getMethod("say", null);
		         method.invoke(obj, null);
		} catch (Exception e) {
		     e.printStackTrace();
		}
	}
}

   

   HelloWolrd类如下:

     

public class HelloWorld {
   public void say(){
	 System.out.println("hello,world");
   }
}

 

  

   我把HelloWorld类放在c:/bin/目录下.

  

   最后谈一下loadClass()和forName()的区别.

   从上可以看出调用loadClass(name),相当于调用loadClass(name,false),表示只加载类,不连接初始化类,调用newInstance()才真正完成连接初始化操作.

    Class.forName("xxxx")等同于Class.forName("xxxx",true,loader).true,表示载入实例的同时也载入静态初始化区块;false,表示只会加载该类别,但不会调用其静态初始化区块,只有等到整个程序第一次实例化某个类时,静态初始化区块才会被调用

    在大多情况下loadClass()和forName()可以互用, 可以把ClassLoader.loadClass()看成是更底层的操作.在某些必须初始化类的场合,比如加载JDBC驱动,只能使用forName()方法了

  

   从上可以看出,实现自己的类加载器相当简单,只要继承一个父类加载器,重写findClass方法就可以了.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值