文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java基础之自定义类加载器

2024-04-02 19:55

关注

一、类加载器关系

在这里插入图片描述

自定义类加载器

创建一个类继承ClassLoader类,同时重写findClass方法,用于判断当前类的class文件是否已被加载

二、基于本地class文件的自定义类加载器

本地class文件路径

在这里插入图片描述

自定义类加载器:


//创建自定义加载器类继承ClassLoader类
public class MyClassLoader extends ClassLoader{
//    包路径
    private String Path;

//    构造方法,用于初始化Path属性
    public MyClassLoader(String path) {
        this.Path = path;
    }

//    重写findClass方法,参数name表示要加载类的全类名(包名.类名)
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        System.out.println("findclass方法执行");

//        检查该类的class文件是否已被加载,如果已加载则返回class文件(字节码文件)对象,如果没有加载返回null
        Class<?> loadedClass = findLoadedClass(name);
//        如果已加载直接返回该类的class文件(字节码文件)对象
        if (loadedClass != null){
            return loadedClass;
        }

//        字节数组,用于存储class文件的字节流
        byte[] bytes = null;
        try {
//            获取class文件的字节流
            bytes = getBytes(name);
        } catch (Exception e) {
            e.printStackTrace();
        }


        if (bytes != null){
//        如果字节数组不为空,则将class文件加载到JVM中
            System.out.println(bytes.length);
//            将class文件加载到JVM中,返回class文件对象
            Class<?> aClass = this.defineClass(name, bytes, 0, bytes.length);
            return aClass;
        }else {
            throw new ClassNotFoundException();
        }
    }

//    获取class文件的字节流
    private byte[] getBytes(String name) throws Exception{
//        拼接class文件路径 replace(".",File.separator) 表示将全类名中的"."替换为当前系统的分隔符,File.separator返回当前系统的分隔符
        String FileUrl = Path + name.replace(".", File.separator) + ".class";
        byte[] bytes;
//        相当于一个缓存区,动态扩容,也就是随着写入字节的增加自动扩容
        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
        File file = new File(FileUrl);
//        创建输入流
        InputStream inputStream = new FileInputStream(file);
        int content;
//        循环将输入流中的所有数据写入到缓存区中
        while ((content = inputStream.read()) != -1){
            arrayOutputStream.write(content);
            arrayOutputStream.flush();
        }
        bytes = arrayOutputStream.toByteArray();
        return bytes;
    }
}

测试类

在这里插入图片描述
在这里插入图片描述

三、遇到的问题

在获取class文件字节流的getBytes方法中,为什么不将输入流中的所有数据直接写入到bytes中,而是要先写入到ByteArrayOutputStream中?如下:

在这里插入图片描述

现在我们尝试将数据直接写入到bytes中,如下:

在这里插入图片描述

但在运行时报错:

Extra bytes at the end of class file com/smallsweets/OutSide

在这里插入图片描述

这是为什么呢?个人理解如下:

看报错提示Extra bytes at the end of:在文件的最后有多余的字节

查看class文件的大小

在这里插入图片描述

但是字节数组在初始化时指定的大小是1024,多余位置的字节是0,所以就出现了多余字节的情况

解决方法是:我们可以在初始化数组时将数组的大小指定为和class文件相同大小,如下:

在这里插入图片描述
这样就可以解决了,虽然可以解决,但如果每次加载类时都要修改未免有些麻烦,所以这里我们直接使用ByteArrayOutputStream,因为它是动态扩容的,也就是大小是随写入数据的多少而动态变化的不会出现多余字节的情况

四、基于网络(url)class文件的自定义类加载器

class文件路径

在这里插入图片描述

自定义类加载器:


public class MyUrlClassLoader extends ClassLoader {
    private String Path;

    public MyUrlClassLoader(String path) {
        this.Path = path;
    }

//    参数name表示全类名(包名.类名)
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
//        判断该类的class文件是否已加载,已加载直接返回class文件对象,没有加载返回null
        Class<?> loadedClass = this.findLoadedClass(name);
        if (loadedClass != null){
            return  loadedClass;
        }

        byte[] bytes = null;
        try {
//            获取网络class文件的字节数组
            bytes = getBytes(Path);
        } catch (Exception e) {
            e.printStackTrace();
        }

//        如果字节数组不为空,将class文件加载到JVM中
        if (bytes != null){
//            将class文件加载到JVM中,参数(全类名,字节数组,起始位置,长度)
            Class<?> aClass = this.defineClass(name, bytes, 0, bytes.length);
            return aClass;
        }else {
            throw new ClassNotFoundException();
        }

    }

//    获取网络class文件的字节流,参数为class文件的url
    private byte[] getBytes(String fileUrl) throws Exception {
        byte[] bytes;
//        创建url对象
        URL url = new URL(fileUrl);
        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
//        连接url
        httpURLConnection.connect();
//        创建输入流,获取网络中class文件的字节流
        InputStream inputStream = httpURLConnection.getInputStream();
//        相当于缓存区,动态扩容
        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
        int content;
//        循环将输入流中的所有数据写入到缓存区中
        while ((content = inputStream.read()) != -1){
            arrayOutputStream.write(content);
            arrayOutputStream.flush();
        }
        bytes = arrayOutputStream.toByteArray();
        return bytes;
    }

}

测试类

在这里插入图片描述
在这里插入图片描述

到此这篇关于Java基础之自定义类加载器的文章就介绍到这了,更多相关Java自定义类加载器内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯