------- 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); } }