黑马程序员-ClassLoader

黑马程序员-ClassLoader

 

---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ---------------------- 

 

概念:

          ClassLoader(类装载器),类加载器是负责加载类的对象。ClassLoader 类是一个抽象类。如果给定类的二进制名称,那么类加载器会试图查找或生成构成类定义的数据。一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的“类文件”。

每个Class对象都包含一个对定义它的ClassLoader的引用。

 

java中的装载器:

  1. BootStrap: 在java虚拟机启动时会用这个装载器来装载JDK安装目录下的jre\lib\rt.jar,也就是java中一些核心的类,如System类,这个装载器底层是用c++写的,是嵌入在jvm中的,所以它不是java类。只是作为一个java中类的起源工具。

 

2.ExtClassLoader:这个类加载器加载JDK安装目录下的/JRE/LIB/ext/*.jar 所有的类 我们只要把我们的类打包成JAR包放在这里即可。这个装载器是一个java类。

 

3.AppClassLoader:我们在java程序中classpath对应的类都有这个AppClassLoader导入进来。这个装载器也是一个java类。

 

类装载器的工作原理和委托模型:

 

     上图是java中类装载器的委托模型,当我们在程序中用到某个类时,jvm首先判断该类在那个类装载器下(即为发起者),然后先用BootStrap这个装载器去找这个类,如果没有就转到ExtClassLoader去装载,再没有就用AppClassLoader这样一级一级的往下找,这就是所谓的父类委托机制。当找到发起者这里时,如果还未找到,就会抛出ClassNotFoundException异常。

  顺便提个小问:我们为什么不利用AppClassLoader下级的加载器呢?

  答:因为AppClassLoader下级可能有多个类加载器多个类加载器相互独立,如果加载类那么就会导致内存中出现多份字节码,造成不必要的的内存浪费。这就是类加载器的委托模型。

 

如何自定义类装载器?

 

        1.首先写一个类继承ClassLoader

            

public class MyClassLoader extends ClassLoader{
	private String attachment;//接收自定义的装载目录。
	public MyClassLoader(){
		
	}
	public MyClassLoader(String attachment){
		this.attachment=attachment;
	}
	public static void main(String[] args) throws Exception  {
		String srcPath=args[0];
		String destPath=args[1]+"\\"+srcPath.substring(srcPath.lastIndexOf('\\')+1);
		FileInputStream in=new FileInputStream(srcPath);
		FileOutputStream out=new FileOutputStream(destPath);
		cypher(in,out);//定义自己类装载器的加解密算法。
		in.close();
		out.close();	
	}
	public static void cypher(InputStream src,OutputStream dest) throws Exception{
		int len=0;
		while((len=src.read())!=-1){
			dest.write(len ^ 0xf);
		}
	}

	@Override
	//要写自己的classloader,建议覆盖findClass方法。若果要覆盖loadClass方法将会很复杂,请参考api。
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		String srcPath=this.attachment+"\\"+name.substring(name.lastIndexOf('.')+1)+".class";
		FileInputStream in=null;
		try {
		    in=new FileInputStream(srcPath);
			ByteArrayOutputStream out=new ByteArrayOutputStream();
			cypher(in, out);
			in.close();
			System.out.println("aaaaa");//	验证是否是自定义类装载器装载
	                byte[] arrs=out.toByteArray();
			return defineClass(arrs, 0, arrs.length);//返回字节码文件对象。
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}

 2.建立自定义装载目录,这里是MyClassPath

      

3.建立测试类测试自定义类装载器

      

//测试自己的类装载器
public class ClassLoaderTest {

	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		//loadClass方法先会检查是否已装载类,然后调用父类的loadClass方法,如果父类类加载器为null,即为Bootstrap加载器,并且没找到class字节码,就调用自己类装载器的findClass方法
		Class clazz=new MyClassLoader("MyClassPath").loadClass("cn.jiava.classloader.MyClassLoaderAttachment");
		Date mAttachment=(Date) clazz.newInstance();
		System.out.println(mAttachment);
		System.out.println(clazz.getClassLoader());
	}

}

 

知识拓展:

    用自定义的类转载器,可以对字节码进行加密和解密,这样可以对class字节码文件又一定的保护作用。

 

 

---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值