我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java中如何自定义一个类加载器

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

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java中如何自定义一个类加载器

如何自定义加载器?

1.创建一个自定义加载器类 继承 ClassLoader 类

2.重写 findClass 方法。 主要是实现从那个路径读取 jar包或者.class文件,将读取到的文件用字节数组来存储,然后可以使用父类的 defineClass 来转换成字节码。

如果想破坏双亲委派的话,就重写 loadClass 方法, 否则不用重写

注意:

1.ClassLoader提供的 protected final Class<?> defineClass(String name, byte[] b, int off, int len) 是用来将字节数组转换成字节码文件的,传入参数 是 (类名,字节数组数据,字节数组读取的开始下标,字节数组的长度)

示例:读取某文件的下的某class文件

创建一个名为MyClassLoader的类加载器:

import java.io.*;

public class MyClassLoader extends ClassLoader{
    String path ;
    MyClassLoader(String dir){
        this.path = dir ;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            this.path = this.path + name +".class";
            File f = new File(path);
            InputStream in = new FileInputStream(f);
            byte [] bys = new byte[  (int)f.length() ];
            int len = 0;
            while( (len = in.read(bys) )!= -1  ){

            }
            // byte[] -> .class
            return defineClass(name,bys,0,bys.length);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return super.findClass(name);
    }
}

测试:

在如下目录,生成一个Hello.class字节码文件

Hello.java:

public class Hello {
    public void sayHello(){
        System.out.println("Hello World!");
    }
}

在这里插入图片描述

测试类:

import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) throws Exception {
        MyClassLoader my = new MyClassLoader("D:\\test\\jvmtest\\");
        Class<?> c1 = my.loadClass("Hello");
        Object o = c1.newInstance();
        Method d = c1.getMethod("sayHello",null);
        d.invoke(o);
    }
}

运行测试类:

在这里插入图片描述

类加载器的使用及自定义类加载器

package com.tech.load.def;
 

public class UserImpl {
    static {
        System.out.println("UserImpl init ...");
    }
}
package com.tech.load.def;
 

public class DefLoader {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //上下文类加载器,默认使用的是 应用程序类加载器
//        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
//        Class<?> c1 = contextClassLoader.loadClass("com.tech.load.def.UserImpl");
//        c1.newInstance(); //classloader.loadClass 不会触发初始化,当创建对象时执行初始化,执行静态程序块内容 输出 "UserImpl init ..."
//        ClassLoader contextClassLoader1 = Thread.currentThread().getContextClassLoader();
//        Class<?> c2 = contextClassLoader1.loadClass("com.tech.load.def.UserImpl");
//        c2.newInstance(); //使用相同的类加载器 加载相同的类名 则加载的是同一个类,c1 c2是同一个类,由于已经初始化过 创建对象不再初始化 不再打印  "UserImpl init ..."
//        System.out.println(contextClassLoader==contextClassLoader1); //true 获取的上下文类加载器是同一个类加载器 
//        System.out.println(c1==c2); // true 同一个类加载器器,加载同名的类,第一次加载时加载的类会缓存到类加载器的缓存,再次加载直接在缓存读取,两次加载的是同一个类
        
        //直接获取类的类加载器 应用程序类加载器
        ClassLoader classLoader = UserImpl.class.getClassLoader();
        ClassLoader classLoader1 = UserImpl.class.getClassLoader();
        System.out.println(classLoader==classLoader1); //true 获取的是同一个应用程序类加载器
       
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        System.out.println(classLoader==contextClassLoader); //true 线程上下文类加载器默认采用的也是应用程序类加载器 与通过类型对象getClassLoader获取方式相同
 
        Class<?> c1 = Class.forName("com.tech.load.def.UserImpl"); //会触发类的初始化
        ClassLoader classLoader2 = c1.getClassLoader();
        System.out.println(classLoader==classLoader2); //true 获取的是同一个应用程序类加载器
        
    }
}

在应用程序中,默认我们获取上下文类加载器、类型对象getClassLoader都是采用的同一个应用程序类加载器,类在第一次被加载后会缓存到类加载器的缓存中,由于是同一个类加载器此时同名的类不能被多次加载,且应用程序类加载器只能加载classpath下的类。

如果我们想加载自定义路径下的类,需要用到自定义类加载器,可以去指定路径下加载类,且通过创建多个类加载器对象,加载的同名类相互隔离,也就是说同名类可以被多个自定义类加载器对象加载。

编写自定义类加载器:

  • 继承ClassLoader;
  • 重写findClass方法在指定路径下进行类的加载,得到字节数组,然后使用defineClass根据字节数组生成字节码文件 也就是class文件;

编写一个测试类Goods放在D盘下,javac得到class文件

 

public class Goods {
    static {
        System.out.println("Goods init ...");
    }
}

javac Goods.java

package com.tech.load.def;
 
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
 

public class DefLoad7 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        MyClassLoader classLoader1 = new MyClassLoader();
        Class<?> c1 = classLoader1.loadClass("Goods");
        Class<?> c2 = classLoader1.loadClass("Goods");
        System.out.println(c1==c2);//true 使用同一个类加载器加载同名类两次,实际只加载了一次,第二次是在类加载器的缓存加载的 结果两次加载的是同一个
        c1.newInstance(); //会初始化
        c2.newInstance(); //不会初始化 
        
        MyClassLoader classLoader2 = new MyClassLoader();
        Class<?> c3 = classLoader2.loadClass("Goods");
        System.out.println(c1==c3); //false 使用不同的类加载器对同一个类进行加载,会得到不同的类型对象
        c3.newInstance(); //会初始化
    }
}
 
//自定义类加载器 加载D盘下的类
class MyClassLoader extends ClassLoader{
    
    //去指定的路径下加载类
    //name是类名称
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String path="D:\\"+name+".class";
        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            //将指定路径下的文件 拷贝到输出流
            Files.copy(Paths.get(path),os);
            byte[] bytes = os.toByteArray();
            //调用父类的方法 根据字节数组生成字节码文件 也就是class文件
            //bytes -> *.class
 
            return defineClass(name,bytes,0,bytes.length);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ClassNotFoundException("类文件未找到",e);
        }
    }
}

使用自定义加载器,创建多个类加载器对象去加载同一个类,会得到多个类型对象。 

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

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

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

Java中如何自定义一个类加载器

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java中如何自定义一个类加载器

这篇文章主要介绍了Java中如何自定义一个类加载器,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2022-11-21

如何在 Java 中自定义类加载器?(java怎么自定义类加载器)

在Java开发中,类加载器是一个非常重要的组件,它负责加载类文件并将其转换为Java虚拟机(JVM)可以理解的形式。默认情况下,Java提供了一些内置的类加载器,如引导类加载器(BootstrapClassLoader)、扩展类加载器(ExtensionClassLoader)和
如何在 Java 中自定义类加载器?(java怎么自定义类加载器)
Java2024-12-17

怎么在java中自定义一个类加载器

本篇文章为大家展示了怎么在java中自定义一个类加载器,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。如果要使用自定义类加载器加载class文件,就需要继承java.lang.ClassLoader类
2023-05-30

java自定义类加载器如何实现类隔离

这篇文章主要介绍了java自定义类加载器如何实现类隔离问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2022-11-21

java怎么自定义类加载器

要自定义类加载器,可以按照以下步骤进行:1. 创建一个类,继承自java.lang.ClassLoader类,覆盖其中的findClass()方法。在findClass()方法中,根据自定义的类加载逻辑,加载指定的类文件并返回一个Class
2023-09-14

java类加载器怎么自定义

要自定义Java类加载器,可以继承ClassLoader类,并重写它的findClass()方法。下面是一个简单的示例:```javapublic class MyClassLoader extends ClassLoader {@Over
2023-09-14

在 Java 中怎样定义一个类?(java如何定义一个类)

在Java编程中,定义一个类是构建程序的基础步骤。类是对象的模板,它定义了对象的属性和行为。以下是在Java中定义一个类的详细步骤:一、类的声明在Java中,使用class关键字来声明一
在 Java 中怎样定义一个类?(java如何定义一个类)
Java2024-12-21

如何在Java中自定义一个枚举类

本文章向大家介绍如何在Java中自定义一个枚举类的基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。Java的特点有哪些Java的特点有哪些1.Java语言作为静态面向对象编程语言的代表,实现了面向对象理论,允许程序
2023-06-06

Java通过自定义类加载器实现类隔离

类隔离是一种通过类加载器实现加载所需类的实现方式,使得不同版本类间隔离,避免了使用冲突问题。本文将通过自定义的类加载器实现类隔离,感兴趣的可以了解一下
2022-11-13

Java自定义类加载器实现类隔离详解

由于每种组件的不同版本所依赖的jar包不同,我们可以借鉴tomcat的实现方式,通过自定义类加载器打破双亲委派机制来实现类隔离,从而达到操作多组件多版本的目的。本文就来和大家详细聊聊实现方法
2023-03-02

Java怎么自定义类加载器实现类隔离

这篇“Java怎么自定义类加载器实现类隔离”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java怎么自定义类加载器实现类隔离
2023-07-05

JVM类加载:如何手写自定义类加载器,命名空间详解

类加载器是负责加载类的对象。类加载器是一个抽象类。给定类的二进制名,类加载器应该尝试定位或生成构成类定义的数据(回去查找对应的class文件如果没有解析成class文件)。一个典型的策略是将名称转换为文件名,然后从文件中读取该名称的“类文件

如何在Java中自定义封装一个JDBC工具类

如何在Java中自定义封装一个JDBC工具类?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。步骤① 创建配置文件(config.properties),用于存放注册驱动和连接
2023-06-06

在 Java 中如何定义一个 List?(java如何定义一个list)

在Java编程中,List是一种常用的集合数据结构,用于存储一组有序的元素。它提供了丰富的操作方法,方便对元素进行添加、删除、查询等操作。以下是在Java中定义一个List的详细步骤:一、导入相关的类库在Java
在 Java 中如何定义一个 List?(java如何定义一个list)
Java2024-12-16

在 Java 中如何自定义异常类?(java中怎么自定义异常类)

在Java编程中,异常处理是一个非常重要的方面。除了使用Java内置的异常类,我们还可以自定义异常类来满足特定的需求。自定义异常类可以提供更详细的错误信息,帮助开发人员更好地理解和处理程序中的错误。一、为什么要自定义异常类?
在 Java 中如何自定义异常类?(java中怎么自定义异常类)
Java2024-12-14

Android如何自定义加载圈

本篇内容介绍了“Android如何自定义加载圈”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
2023-07-02

使用Java如何自定义一个迭代器

使用Java如何自定义一个迭代器?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。具体如下:编写自己的Iterator,实现Iterator接口,这里多说一句,实现Iterab
2023-05-31

Keras中如何定义一个自定义的层

要定义一个自定义的层,需要继承keras.layers.Layer类,并重写__init__和call方法。下面是一个简单的示例:import tensorflow as tffrom tensorflow import kerasf
Keras中如何定义一个自定义的层
2024-03-14

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录