You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 17下如何让自定义类加载器接管后续类加载?

问题原因

你遇到的问题核心是Java类加载的双亲委派模型:当你用自定义类加载器加载com.mycompany.app.Test时,自定义加载器会先委托父加载器(即加载App的系统类加载器)尝试加载Test类。如果Test类存在于系统类路径中,父加载器会成功加载它,此时Test类的定义类加载器是系统类加载器,而非你创建的自定义加载器。当Test类中实例化Test2时,JVM会使用加载Test的类加载器(系统类加载器)去查找Test2,而Test2不在系统类路径中,因此抛出NoClassDefFoundError。

解决方案(不修改Test类,仅修改main方法)

你需要自定义类加载器,打破双亲委派模型中对Test类的委托逻辑,让自定义加载器优先加载Test类。这样Test的定义类加载器就是你的自定义加载器,后续加载Test2时会使用这个能找到Test2的加载器。

具体修改步骤

  1. 在App类中定义一个继承URLClassLoader的自定义类加载器,重写loadClass方法,对Test类跳过双亲委派、优先自行加载:
static class CustomClassLoader extends URLClassLoader {
    public CustomClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        // 仅对Test类优先自行加载,其他类遵循双亲委派
        if ("com.mycompany.app.Test".equals(name)) {
            synchronized (getClassLoadingLock(name)) {
                Class<?> loadedClass = findLoadedClass(name);
                if (loadedClass == null) {
                    loadedClass = findClass(name);
                }
                if (resolve) {
                    resolveClass(loadedClass);
                }
                return loadedClass;
            }
        }
        return super.loadClass(name, resolve);
    }
}
  1. 在main方法中,用这个CustomClassLoader替换原来的URLClassLoader:
// 替换原ClassLoader创建代码
ClassLoader classLoader = new CustomClassLoader(classPaths, App.class.getClassLoader());

修改后,Test类会被自定义加载器加载,当Test中实例化Test2时,JVM会使用该自定义加载器从指定jar中查找并加载Test2,test.ex()即可正常执行。

备选方案(需调整类路径)

如果允许将Test类从系统类路径中移除,放到自定义加载器指向的jar包或路径中,原有的URLClassLoader会因为父加载器找不到Test类,自行加载Test,同样能解决问题。但该方案需要调整类文件存放位置,若你要求仅修改main方法,优先选择自定义类加载器方案。

内容的提问来源于stack exchange,提问作者Runekn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 17:19:03