自定义类的加载器

1 篇文章 0 订阅

一、目标

通过自定义加载器动态加载一个本地.class类文件,得到该类的class对象

二、代码分析

package com.lyz.classloader;

import java.io.*;

public class FileClassLoader extends ClassLoader {
    private String rootPath;

    public FileClassLoader(String rootPath) {
        this.rootPath = rootPath;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        //查看名为“name”的类是否被加载
        Class<?> aClass = this.findLoadedClass(name);


        if(aClass == null) {
            try {
                //双亲委派机制
                aClass = this.getParent().loadClass(name);
            } catch (ClassNotFoundException e) {
                //异常可以忽略
                //e.printStackTrace();
            }
            if(aClass == null) {
                byte[] buffer = getClassData(name);
                aClass = defineClass(name, buffer, 0, buffer.length);
            } else {
                return aClass;
            }
        } else {
            return aClass;
        }
        return aClass;
    }

    private byte[] getClassData(String name) {
        String pathClass = rootPath +File.separator+ name.replace(".",File.separator)+".class";
        InputStream inputStream = null;
        ByteArrayOutputStream baos = null;
        try {
            inputStream = new FileInputStream(pathClass);
            baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while((len=inputStream.read(buffer))!=-1) {
                baos.write(buffer, 0, len);
            }

            return baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if (inputStream!=null)
                    inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(baos!=null)
                    baos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

2.1为什么要使用ByteArrayOutputStream流

下面解释以下getClassData方法中为什么要用到ByteArrayOutputStream流,因为数组在定义的时候就必须确定长度,而我们如果不使用ByteArrayOutputStream流的toByteArray方法,就无法返回一个长度恰好等于.class文件的字节数组。

2.2 四个方法loadClass,findClass,findloadClass,defineClass

2.2.1findloadClass(String name)方法

查找已加载过的名为name(注:带包的全类名)的类,返回对应的class对象

2.2.2findClass(String name)方法

查找名为name的类,返回对应class对象

2.2.3defineClass(String name,byte[] b,int off,int len)

把字节数组b中的内容转换为java类,返回的结果是对应的class对象。name是全类名,b是已经编译好的.class文件转换成的字节数组,off与len限定了读入的字节数组长度

2.2.4loadClass(String name)

加载名为name的类,此方法定义在ClassLoader类中,采用了双亲委托机制,首先在已加载的类中寻找,然后Bootstrap ClassLoader中,再Extension ClassLoader,再Application ClassLoader,最后才是自定义的加载器
,若要改变加载顺序,则重写此方法,但是不建议。

三、测试

package com.lyz.classloader;

public class Text {
    public static void main(String[] args) {
        FileClassLoader fcl = new FileClassLoader("f:");
        Class<?> aClass1 = null;
        try {
            aClass1 = fcl.loadClass("com.lyzh.Text");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(aClass1.hashCode());
        System.out.println(aClass1.getClassLoader());
    }
}

注意,运行程序之前,在路径"F:\com\lyzh"下已经存在Text.class文件
带包的Text类编译时,javac -d . Text.class,“.”表示当前路径
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值