Java自定义类加载器

1. 自定义类加载器要求

        实现目标:自定义一个类加载器,用来加载指定目录下的class文件。

2. 代码实现

2.1 自定义类加载器

package cn.ordinary.test.cl;

import com.google.common.io.Files;

import java.io.File;
import java.io.IOException;

/**
 * 自定义类加载器:用来加载指定目录下的类
 *
 * @author sh
 **/
public class MyClassLoader extends ClassLoader {

    private String classPath;

    public MyClassLoader(String classPath) {
        this.classPath = classPath;
    }

    /**
     * 自定义类加载器,继承 java.lang.ClassLoader 并重写 findClass() 方法 即可。
     * 这个类并没有重写 loadClass()方法,也就是说,并没有破坏 java默认的类加载机制(双亲委派模型)。
     *
     * @param name class文件的全限定名(包名 + 类名)
     * @return java.lang.Class<?>
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] classData = this.loadClassData(name);
            // 调用 defineClass()方法 将 二进制字节码 转换为 Class对象。
            return super.defineClass(name, classData, 0, classData.length);
        } catch (IOException e) {
            throw new ClassNotFoundException(name, e);
        }
    }

    /**
     * 读取 class文件,将其转换为 二进制字节码
     *
     * @param className class文件的全限定名(包名 + 类名)
     * @return byte[] 返回二进制字节码
     */
    private byte[] loadClassData(String className) throws IOException {
        // 将包结构转换为文件路径结构
        className = className.replace('.', File.separatorChar).concat(".class");
        // 从 文件系统 中读取 类的字节码
        return Files.toByteArray(new File(classPath, className));
    }

}

2.2 如何使用自定义类加载器

package cn.ordinary.test.cl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Date 2024/3/12
 * @Author sh
 **/
public class ClassLoaderTest {

    public static void main(String[] args) {
        // 这里的目录由使用者自己去决定
        String classPath = "D:/99-test/cl";
        String className = "cn.o.Emperor";

        // 创建自定义类加载器
        MyClassLoader myClassLoader = new MyClassLoader(classPath);
        try {
            /**
             * 使用 自定义类加载器 加载 指定目录下的 class文件。
             *
             * 注意:这里调用的是 loadClass()方法,也就是说,这里也同样遵循了 java默认的类加载机制(双亲委派模型)。
             */
            Class<?> clazz = myClassLoader.loadClass(className);
            System.out.println("加载[" + className + "]类的类加载器是: " + clazz.getClassLoader());

            // 通过反射创建对象,调用方法等
            Object instance = clazz.newInstance();
            Method sayMethod = clazz.getMethod("say", String.class);
            sayMethod.invoke(instance, "秦始皇");
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
                 | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

}

cn.o.Emperor类如下:我们需要使用 javac 编译该 Emperor.java 文件,将其编译成 Emperor.class文件。

package cn.o;

/**
 * @Date 2024/3/13
 * @Author sh
 **/
public class Emperor {

    public static void say(String name) {
        System.out.println(name + ": “额滴额滴,都是额滴!”。");
    }

}

javac命令如下:

javac -encoding utf8 Emperor

执行ClassLoaderTest类,控制台输入内容如下:

加载[cn.o.Emperor]类的类加载器是: cn.ordinary.test.cl.MyClassLoader@de0a01f
秦始皇: “额滴额滴,都是额滴!”。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值