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

如何动态加载Jar文件到Java项目并解决类找不到异常?

问题分析与解决方案

首先,你遇到的java.lang.ClassNotFoundException核心原因和修正方案如下:

1. Jar文件格式错误

URLClassLoader只能加载编译后的.class字节码文件,而你的Jar中存放的是MyMod.java源文件,这是导致找不到类的根本问题。

  • 修正方式:先将MyMod.java编译为MyMod.class,再重新打包Jar,正确的Jar结构应为:
    file.jar
    |_ mymod (文件夹)
          |_ MyMod.class
    

2. 代码中的其他问题修正

即使Jar格式正确,现有代码还有几个影响类加载的问题需要调整:

(1)ClassLoader父加载器未正确设置

要支持Jar中子类QueenBee继承项目中的父类Bee,必须让URLClassLoader能访问项目的类路径。默认URLClassLoader的父加载器是系统类加载器,可能无法访问你的项目类,因此需要指定当前类的加载器作为父加载器:

URLClassLoader classLoader = new URLClassLoader(new URL[]{file.toURI().toURL()}, this.getClass().getClassLoader());

(2)文件扩展名判断不严谨

getFileExtension方法可能存在大小写(比如Jar文件是.JAR)或多扩展名(比如test.jar.bak)判断错误,可替换为更可靠的实现:

private static String getFileExtension(File file) {
    String name = file.getName();
    int lastDotIndex = name.lastIndexOf('.');
    return lastDotIndex == -1 ? "" : name.substring(lastDotIndex + 1).toLowerCase();
}

(3)未处理IOException

file.toURI().toURL()会抛出IOException,需要在try-catch中捕获或声明抛出。

(4)重复创建ClassLoader的资源浪费

循环中每次创建新的URLClassLoader会消耗不必要的资源,建议收集所有Jar的URL后统一创建一个ClassLoader。

修正后的完整代码示例

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class JarLoader {
    public static void loadMods() {
        String homeDir = System.getProperty("user.home");
        String modsPath = homeDir + File.separator + "AppData" + File.separator + "Roaming" + File.separator + ".minecraft" + File.separator + "mods";
        File modsFolder = new File(modsPath);

        if (!modsFolder.exists() || !modsFolder.isDirectory()) {
            return;
        }

        List<URL> jarUrls = new ArrayList<>();
        // 收集所有Jar文件的URL
        for (File file : Objects.requireNonNull(modsFolder.listFiles())) {
            if (getFileExtension(file).equals("jar")) {
                try {
                    jarUrls.add(file.toURI().toURL());
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }
            }
        }

        // 统一创建ClassLoader,指定父加载器为当前类的加载器
        try (URLClassLoader classLoader = new URLClassLoader(jarUrls.toArray(new URL[0]), JarLoader.class.getClassLoader())) {
            // 加载并调用MyMod类的scanMods方法
            Class<?> modClass = classLoader.loadClass("mymod.MyMod");
            Method scanMethod = modClass.getDeclaredMethod("scanMods");
            scanMethod.invoke(modClass); // 静态方法也可传null作为invoke参数
        } catch (IOException | ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private static String getFileExtension(File file) {
        String name = file.getName();
        int lastDotIndex = name.lastIndexOf('.');
        return lastDotIndex == -1 ? "" : name.substring(lastDotIndex + 1).toLowerCase();
    }
}

继承场景的支持说明

只要URLClassLoader的父加载器设置正确(能访问项目中的Bee类),Jar中的QueenBee类无需包含Bee类,就能正常继承并被加载调用——这符合Java的双亲委派模型:ClassLoader会先通过父加载器查找Bee类,父加载器找不到才会尝试自己加载。

是否需要更换URLClassLoader?

不需要,URLClassLoader完全能满足你的需求。如果是Java 9及以上版本,也可以考虑使用ModuleLayer实现模块化加载,但对于你的场景,URLClassLoader更简单直接,修正上述问题后即可正常工作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 15:02:56