黑马程序员——高新技术(类加载器)

------- android培训、java培训、期待与您交流! ----------

类加载器:

1、java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap------>ExtClassLoader-------->AppClassLoader

2、类加载器也是java类,因为其它是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器,就是BootStrap(不是java类)。

类加载器的委托机制:

java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?

1、首先当前线程的类加载器去加载线程中的第一个类;

2、如果类A中引用了类Bjava虚拟机将使用加载类A的类加载器来加载类B

3、还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

4、每个类加载器加载类时,又先委托给其上级类加载器(当所有祖宗类加载器没有加载到类,就回到发起者类加载器,如还加载不了,则抛ClassNotFoundException,而不是再去找发起者类加载器的的儿子)。

类加载器管辖范围:

黑马程序员——高新技术(类加载器)_第1张图片


获得类加载器实例:

public class ClassLoaderTest {
	public static void main(String[] args)throws Exception {
		System.out.println(ClassLoaderTest.class.getClassLoader().getClass()
				.getName());//打印类加载器名字
		System.out.println(System.class.getClassLoader());//打印System类的加载器
		ClassLoader loader=ClassLoaderTest.class.getClassLoader();
		while(loader!=null){//此处用于测试本类加载的时候到底有几个加载器,以及他们的层次结构
			System.out.println(loader.getClass().getName());
			loader=loader.getParent();
		}
		System.out.println(loader);
	}
}


编写自己的类加载器步骤:

1、定义一个类继承ClassLoader类;

2、覆盖findClass方法,在覆盖过程中调用defineClass来创建实例类返回。

如下综合实例:编写自己的类加载器,并加密文件,这样就只能由自己的类加载器来进行加载

自己的类加载器:

package cn.itcast.day2;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class MyClassLoader extends ClassLoader {
	public static void main(String[] args)throws Exception {
		// TODO Auto-generated method stub
		String srcPath=args[0];/*主函数参数,在运行时需输入主函数参数,如本例中需输入
	E:\javaproject-test\javaEnhance\bin\cn\itcast\day2\ClassLoaderAttachment.class itcastlib*/
		String destDir=args[1];//主函数参数
		FileInputStream fis=new FileInputStream(srcPath);//读取文件
		String destFileName=srcPath.substring(srcPath.lastIndexOf("\\")+1);//获取目标文件名
		String destPath=destDir+"\\"+destFileName;//获取加密后的文件的存放路径
		FileOutputStream fos=new FileOutputStream(destPath);//写入文件
		cypher(fis,fos);//文件加密
		fis.close();//关闭资源
		fos.close();	
	}
	//此方法用于对文件加密
	private static void cypher(InputStream ips,OutputStream ops)throws Exception{
		int b=-1;
		while((b=ips.read())!=-1){
			ops.write(b^0xff);
		}
	}
	String classDir;
	@Override
	//覆盖findClass方法
	protected Class<?> findClass(String name)throws ClassNotFoundException{
		String classFileName=classDir+"\\"+name.substring(name.lastIndexOf(".")+1)+".class";
		try {
			FileInputStream fis = new FileInputStream(classFileName);
			ByteArrayOutputStream bos=new ByteArrayOutputStream();
			cypher(fis,bos);//解密文件
			fis.close();
			System.out.println("my classloader");//用于测试是否是自己的类加载器进行加载的
			byte[] bytes=bos.toByteArray();
			return defineClass(bytes, 0, bytes.length);	//返回字节码文件
		} catch (Exception e) {
			System.out.println("流异常");
		}
		return super.findClass(name);
	}
	public MyClassLoader(){	
	}
	public MyClassLoader(String classDir){//带参数的构造函数
		this.classDir=classDir;
	}	
}
定义一个用于做加密测试的类:

package cn.itcast.day2;
import java.util.Date;
public class ClassLoaderAttachment extends Date {
	@Override
	public String toString(){
		return "hello itcast";	
	}
}
定义一个主类,用于测试自己定义的类加载器是否正确:

package cn.itcast.day2;
import java.util.Date;
public class ClassLoaderTest {
	public static void main(String[] args)throws Exception {
/*1、执行此步骤时,若先用加密后的文件ClassLoaderAttachment.class覆盖掉cn.itcast.day2下的ClassLoaderAttachment.class文件,则父类加载器加载此文件时就会报错,无法识别,因为已加密;
2、执行此步骤时,如先删掉cn.itcast.day2下的ClassLoaderAttachment.class文件,则父类加载器就无法找到,这时就会由自己定义的加载器进行加载。*/
		Class clazz=new MyClassLoader("itcastlib").loadClass("cn.itcast.day2.ClassLoaderAttachment");
		Date d1=(Date)clazz.newInstance();
		System.out.println(d1);
	}
}



你可能感兴趣的:(类加载器,类加载器委托机制)