Java基础之自定义类加载器

 更新时间:2021年05月13日 08:59:57   作者:SmallSweets  
应该有很多小伙伴还不了解Java自定义类加载器吧,下文中有对Java自定义类加载器非常详细的描述,还有小伙伴们最喜欢的代码环节,需要的朋友可以参考下

一、类加载器关系

在这里插入图片描述

自定义类加载器

创建一个类继承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自定义类加载器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 解决eclipse中maven引用不到已经存在maven中jar包的问题

    解决eclipse中maven引用不到已经存在maven中jar包的问题

    这篇文章主要介绍了解决eclipse中maven引用不到已经存在maven中jar包的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • Spring Boot中使用Server-Sent Events (SSE) 实现实时数据推送教程

    Spring Boot中使用Server-Sent Events (SSE) 实

    Server-Sent Events (SSE) 是HTML5引入的一种轻量级的服务器向浏览器客户端单向推送实时数据的技术,本文主要介绍了Spring Boot中使用Server-Sent Events (SSE) 实现实时数据推送教程,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • java类加载机制、类加载器、自定义类加载器的案例

    java类加载机制、类加载器、自定义类加载器的案例

    这篇文章主要介绍了java类加载机制、类加载器、自定义类加载器的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • Java如何随机生成图片验证码

    Java如何随机生成图片验证码

    这篇文章主要为大家详细介绍了Java如何随机生成图片验证码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12
  • Java NIO与IO的区别以及比较

    Java NIO与IO的区别以及比较

    这篇文章主要介绍了Java NIO与IO的区别以及比较,文章通过围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • BiConsumer接口中的方法andThen accept使用详解

    BiConsumer接口中的方法andThen accept使用详解

    这篇文章主要为大家介绍了BiConsumer接口中的方法andThen accept使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • 三种简单排序算法(使用java实现)

    三种简单排序算法(使用java实现)

    下面小编就为大家带来一篇三种简单排序算法(使用java实现)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-07-07
  • Java实现远程控制技术完整源代码分享

    Java实现远程控制技术完整源代码分享

    这篇文章主要为大家详细介绍了Java实现远程控制技术完整源代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • Spring框架之IOC介绍讲解

    Spring框架之IOC介绍讲解

    IOC-Inversion of Control,即控制反转。它不是什么技术,而是一种设计思想。这篇文章将为大家介绍一下Spring控制反转IOC的原理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • spring 如何将配置信息注入静态变量的方法

    spring 如何将配置信息注入静态变量的方法

    本篇文章主要介绍了spring 如何将配置信息注入静态变量的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06

最新评论