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

时间:2023-02-17 18:15:14
 

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

分类: Java基础知识 107人阅读 评论(0) 收藏 举报 类加载器类加载器委托机制

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

类加载器:

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

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

类加载器的委托机制:

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

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

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

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

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

类加载器管辖范围:

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


获得类加载器实例:

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


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

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

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

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

自己的类加载器:

[java] view plaincopy
  1. package cn.itcast.day2;  
  2. import java.io.ByteArrayOutputStream;  
  3. import java.io.FileInputStream;  
  4. import java.io.FileOutputStream;  
  5. import java.io.InputStream;  
  6. import java.io.OutputStream;  
  7. public class MyClassLoader extends ClassLoader {  
  8.     public static void main(String[] args)throws Exception {  
  9.         // TODO Auto-generated method stub  
  10.         String srcPath=args[0];/*主函数参数,在运行时需输入主函数参数,如本例中需输入 
  11.     E:\javaproject-test\javaEnhance\bin\cn\itcast\day2\ClassLoaderAttachment.class itcastlib*/  
  12.         String destDir=args[1];//主函数参数  
  13.         FileInputStream fis=new FileInputStream(srcPath);//读取文件  
  14.         String destFileName=srcPath.substring(srcPath.lastIndexOf("\\")+1);//获取目标文件名  
  15.         String destPath=destDir+"\\"+destFileName;//获取加密后的文件的存放路径  
  16.         FileOutputStream fos=new FileOutputStream(destPath);//写入文件  
  17.         cypher(fis,fos);//文件加密  
  18.         fis.close();//关闭资源  
  19.         fos.close();      
  20.     }  
  21.     //此方法用于对文件加密  
  22.     private static void cypher(InputStream ips,OutputStream ops)throws Exception{  
  23.         int b=-1;  
  24.         while((b=ips.read())!=-1){  
  25.             ops.write(b^0xff);  
  26.         }  
  27.     }  
  28.     String classDir;  
  29.     @Override  
  30.     //覆盖findClass方法  
  31.     protected Class<?> findClass(String name)throws ClassNotFoundException{  
  32.         String classFileName=classDir+"\\"+name.substring(name.lastIndexOf(".")+1)+".class";  
  33.         try {  
  34.             FileInputStream fis = new FileInputStream(classFileName);  
  35.             ByteArrayOutputStream bos=new ByteArrayOutputStream();  
  36.             cypher(fis,bos);//解密文件  
  37.             fis.close();  
  38.             System.out.println("my classloader");//用于测试是否是自己的类加载器进行加载的  
  39.             byte[] bytes=bos.toByteArray();  
  40.             return defineClass(bytes, 0, bytes.length); //返回字节码文件  
  41.         } catch (Exception e) {  
  42.             System.out.println("流异常");  
  43.         }  
  44.         return super.findClass(name);  
  45.     }  
  46.     public MyClassLoader(){   
  47.     }  
  48.     public MyClassLoader(String classDir){//带参数的构造函数  
  49.         this.classDir=classDir;  
  50.     }     
  51. }  
定义一个用于做加密测试的类:

[java] view plaincopy
  1. package cn.itcast.day2;  
  2. import java.util.Date;  
  3. public class ClassLoaderAttachment extends Date {  
  4.     @Override  
  5.     public String toString(){  
  6.         return "hello itcast";    
  7.     }  
  8. }  
定义一个主类,用于测试自己定义的类加载器是否正确:

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