代码改变世界

黑马程序员-张老师加强6-类加载器

2014-06-07 01:01  黑马程序员*  阅读(362)  评论(0编辑  收藏  举报

类加载器:

基本概念:

一般来说:java文件(源程序)经过编译器被转换成java字节码。类加载器负责读取字节码文件,并转换成java.lang.class的一个实例对象。每个这样的实例代表一个java类。通过实例的newInstance方法,就可以创建出该类一个对象。

Java.lang.ClassLoader类的介绍:

ClassLoader类的基本职责就是根据指定的类的名称,找到或生产对应的字节码,然后从这些字节码中定义出一个java类。即,java.lang.Class的一个实例。

常用方法:

LoadClass(String name);加载名称为name的类,返回结果是java.lang.Class的实例

findClass(String name):查找名称为name的已经被加载过的类,返回ava.lang.Class的实例。

defineClass(String name,byte[] b,int off,int,len);将字节数组b转成java类。

Java默认三个主要类加载器:

BootStrap,ExtClassLoader,AppClassLoader

BootStrap:用于加载其他类加载器。

类加载器之间的父子关系和管辖范围图

加载器的委托机制:

  每个类加载器加载类时,又先委托给其上级类加载器。(避免出现多字解码现象) 这就是委托机制。

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

  如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。 但是类加器要去找上级的类加载,然后再找上一级累加器,

      如果找不到,则返回发起者。发起者如果也找不到,则报异常,不会再找下一级。

自定义类加器步骤:

  继承ClassLoader类。

  复写findclass(String);

自定义类加载器的加载过程:

  1.调用 findLoadedClass(String) 来检查是否已经加载类

  2.委托给父类加载器,父类加载器调用loadClass 方法

  3.loadClass调用调用 findClass(String) 方法查找类。

  4.如果找不到,发起者再找。

如何实现父类加载器查找不到我们的文件呢?

  类加载器必须在它字节的目录下才能加载。我们可以控制类文件存放的目录。 

package cn.itcast;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class DemoCLassLoader extends ClassLoader{ 
    public static void main(String[] args) throws Exception {
         String resPath = args[0];//需要被加密的文件。args[0]=D:\javaxue学习\test\src\cn\itcast\ClassLoaderDemo.java
    //     String desPath = args[1];//加密后的文件存方法的路径名。
        File file = new File(resPath);
        if(!file.exists()){throw new RuntimeException("文件不存在");}
        FileInputStream in = new FileInputStream(file);
        System.out.println("'fa");
        //将加载后的文件扔保存到resPath的路径下。
        int index = resPath.lastIndexOf("\\")+1;
        String filepath = resPath.substring(0,index);//获取路径名
        File file1 = new File(filepath+"加密"+".class");//加密后存储文件。
        System.out.println(file1);
        FileOutputStream os= new FileOutputStream(file1);
         cypher(in,os);        
    }    
    //加密
    public static void cypher(InputStream in,OutputStream os) throws Exception{    
        int len = -1;
        while((len=in.read())!=-1){
            os.write(len&255);             
        }        
        in.close();
        os.close();
    }
     
    //要加载的文件的路径
    public  DemoCLassLoader() {         
    }
    private String dir;
    public  DemoCLassLoader(String dir) {
         this.dir=dir;
    }
     
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
     //使用类加载器并解密 :name是要加载的文件的名字        
        try {
             String path = dir+name+".class";
             FileInputStream fis = new FileInputStream(path);
             //创建缓存
             ByteArrayOutputStream fos = new ByteArrayOutputStream();
             cypher(fis,fos);
             byte[] buf = fos.toByteArray();
             //创建实例对象
             System.out.println(new String(buf, 0, buf.length));
             return defineClass(buf, 0, buf.length);            
        }
        catch (Exception e) {             
            e.printStackTrace();
        }
        return super.findClass(name);
    }    
}