您的位置:首页 > 其它

类加载器的委托机制、自定义类加载器

2014-06-22 18:29 267 查看
**
 * 类加载器
1、每个ClassLoader本身只能分别加载特定位置和目录中的类,但它们可以委托其他的 
   类装载器去加载类,这就是类加载器的委托模式。
   
2、类装载器一级级委托到BootStrap类加载器,当BootStrap无法加载当前所要加载的 类时,
        然后才一级级回退到子孙类装载器去进行真正的加载。当回退到最初的类装 载器时,
        如果它自己也不能完成类的装载,那就应报告ClassNotFoundException异 常。

3、当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
        首先当前线程的类加载器去加载线程中的第一个类。
        因为线程中有自己的类加载器,线程中的类都可以指定自己的类加载器。
        如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。 
        还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

4、每个类加载器加载类时,又先委托给其上级类加载器。

        当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛      
        ClassNotFoundException,不是再去找发起者类加载器的儿子,
        因为没有getChild 方法,即使有,那有多个儿子,找哪一个呢?
5、对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest 
输出成 jre/lib/ext目录下的itcast.jar包中后,运行结果为      ExtClassLoader的原因。
自定义类加载器
知识讲解:
        自定义的类加载器的必须继承ClassLoader
        loadClass方法与findClass方法
        defineClass方法
编程步骤:
            编写一个对文件内容进行简单加密的程序。
            编写了一个自己的类装载器,可实现对加密过的类进行装载和解密。
            编写一个程序调用类加载器加载类,在源程序中不能用该类名定义引用变量,
            因为编译器无法识别这个类。程序中可以除了使用ClassLoader.load方法之外,
            还可以使用设置线程的上下文类加载器或者系统类加载器,然后再使用Class.forName。

实验步骤:
            对不带包名的class文件进行加密,加密结果存放到另外一个目录,例如: java MyClassLoader MyTest.class F:\itcast
            运行加载类的程序,结果能够被正常加载,但打印出来的类装载器名称为AppClassLoader:java MyClassLoader MyTest F:\itcast
            用加密后的类文件替换CLASSPATH环境下的类文件,再执行上一步操作就出问题了,错误说明是AppClassLoader类装载器装载失败。
 *
 */

/**在项目下建一个文件夹,把未加密 的目标class文件   加密并写入该文件夹
 * 然后用该类解密该文件,获取该字节码文件对象
 * @author yaomaokai
 *
 */
import java.io.*;
public class MyClassLoader extends ClassLoader
{

    public static void main(String[] args) throws Exception
    {
        String srcPath = args[0];
        //截取文件名
        String fileNmae = srcPath.substring(srcPath.lastIndexOf("\\") + 1);
        //目标路径
        String destDir = args[1];
        //目标路径+截取的文件名组成目标绝对路径
        String destPath = destDir + "\\" + fileNmae;
        
        FileInputStream fis = new FileInputStream(srcPath);
        FileOutputStream fos = new FileOutputStream(destPath);
       //加密
        syhpern(fis, fos);
        fis.close();
        fos.close();

    }
//输入流加密到输出流
    private static void syhpern(InputStream ips, OutputStream ops)
            throws Exception
    {
        int b = 0;
        while ((b = ips.read()) != -1)
        {//加密后写入输出流
            ops.write(b ^ 0xff);
        }
    }
    private String classPath;

    public MyClassLoader()
    {

    }
//类加载器传入目标路径
    public MyClassLoader(String classPath)
    {
        this.classPath = classPath;
    }

    @Override//传入一个字节码文件名,重写父类的findClass方法,返回该类的字节码文件对象
    protected Class<?> findClass(String name) throws ClassNotFoundException
    {
        String classFileName=classPath+"\\"+name+".class";
        try
        {       //字节输入流读取未解密的文件
            FileInputStream fis = new FileInputStream(classFileName);
            System.out.println(classFileName);
            //字节数组输出流
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            //解密
            syhpern(fis,bos);
            fis.close();
            //字节输出流变成字节数据
           byte[] buff= bos.toByteArray();
           //传入该字节数组 返回字节码对象
           return defineClass(buff, 0, buff.length);
        } catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // TODO Auto-generated method stub
        return null;
    }

}

测试类

public class Test
{

    /**
     * @param args
     * @throws ClassNotFoundException 
     * @throws IllegalAccessException 
     * @throws InstantiationException 
     */
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException
    {
       
        MyClassLoader loader = new MyClassLoader("itcastlib");
       Class clazz = loader.loadClass("Itheima");
       Object obj =clazz.newInstance();
       System.out.println(obj);
    }

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: