黑马程序员——高新技术(类加载器)
分类: Java基础知识2013-09-17 18:17 107人阅读 评论(0) 收藏 举报 类加载器类加载器委托机制------- android培训、java培训、期待与您交流! ----------
类加载器:
1、java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap------>ExtClassLoader-------->AppClassLoader;
2、类加载器也是java类,因为其它是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器,就是BootStrap(不是java类)。
类加载器的委托机制:
当java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
1、首先当前线程的类加载器去加载线程中的第一个类;
2、如果类A中引用了类B,java虚拟机将使用加载类A的类加载器来加载类B;
3、还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
4、每个类加载器加载类时,又先委托给其上级类加载器(当所有祖宗类加载器没有加载到类,就回到发起者类加载器,如还加载不了,则抛ClassNotFoundException,而不是再去找发起者类加载器的的儿子)。
类加载器管辖范围:
编写自己的类加载器步骤:获得类加载器实例:
- 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);
- }
- }