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

相关文章

  • 关于JAVA中stream流的基础处理(获取对象字段和对象批量处理等)

    关于JAVA中stream流的基础处理(获取对象字段和对象批量处理等)

    这篇文章主要介绍了关于JAVA中stream流的基础处理,包含获取对象字段、按字段排序、按字段去重、对象批量处理、指定字段转数组等内容,需要的朋友可以参考下
    2023-03-03
  • Java中的异常处理机制try-catch详解

    Java中的异常处理机制try-catch详解

    这篇文章主要介绍了Java中的异常处理机制try-catch详解,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-12-12
  • 基于java ssm springboot实现选课推荐交流平台系统

    基于java ssm springboot实现选课推荐交流平台系统

    这篇文章主要介绍了选课推荐交流平台系统是基于java ssm springboot来的实现的,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08
  • Java中Volatile关键字能保证原子性吗

    Java中Volatile关键字能保证原子性吗

    这篇文章主要介绍了Java中Volatile关键字能保证原子性吗,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-08-08
  • spring整合mybatis的底层原理分析

    spring整合mybatis的底层原理分析

    这篇文章主要介绍了spring整合mybatis的底层原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-05-05
  • springmvc注解配置实现解析

    springmvc注解配置实现解析

    这篇文章主要介绍了springmvc注解配置实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • spring boot 实现热部署的几种方式及配置方法

    spring boot 实现热部署的几种方式及配置方法

    这篇文章主要介绍了spring boot 实现热部署的几种方式及配置方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2025-05-05
  • Java基础之异常处理操作示例

    Java基础之异常处理操作示例

    这篇文章主要介绍了Java基础之异常处理操作,涉及java异常捕获、抛出异常、自定义异常处理相关操作技巧,需要的朋友可以参考下
    2019-08-08
  • Spark Streaming编程初级实践详解

    Spark Streaming编程初级实践详解

    这篇文章主要为大家介绍了Spark Streaming编程初级实践详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • Netty学习教程之Netty与Marshalling结合发送对象

    Netty学习教程之Netty与Marshalling结合发送对象

    Netty是由JBOSS提供的一个Java开源框架,之前已经给大家简单介绍了一些基础与使用,下面这篇文章主要给大家介绍了关于Netty与Marshalling结合发送对象的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-05-05

最新评论