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

JDK11如何从指定包加载所有类?已尝试方法遇迭代查找问题

在JDK11中检索指定包下的类

首先,你提到的ClassLoader.getSystemClassLoader().getDefinedPackages()方法返回的是Package[]数组,本身是可以迭代的,比如:

Package[] loadedPackages = ClassLoader.getSystemClassLoader().getDefinedPackages();
for (Package pkg : loadedPackages) {
    System.out.println("已加载的包:" + pkg.getName());
}

但这个方法只能获取已经被类加载器加载过的包,无法主动扫描指定包下的所有类,也无法查找未加载的类——因为JDK类加载器是按需加载类的,不会预先扫描所有类文件。

要实现指定包下的类检索,JDK11本身没有提供直接的API,需要自己实现扫描逻辑,或者借助第三方库。以下是原生JDK的实现方案:

原生扫描实现(支持文件系统与Jar包)

下面的工具类可以扫描指定包下的所有类,涵盖文件系统目录和Jar包两种常见场景:

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class PackageScanner {
    public static List<Class<?>> scanClasses(String packageName) throws IOException, ClassNotFoundException {
        List<Class<?>> classList = new ArrayList<>();
        String packagePath = packageName.replace('.', '/');
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Enumeration<URL> resources = classLoader.getResources(packagePath);

        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            switch (resource.getProtocol()) {
                case "file":
                    scanFileSystemDirectory(new File(resource.getFile()), packageName, classList);
                    break;
                case "jar":
                    scanJarFile((JarURLConnection) resource.openConnection(), packagePath, packageName, classList);
                    break;
                // 可扩展支持其他协议,如jrt(模块化JDK的模块路径)
            }
        }
        return classList;
    }

    private static void scanFileSystemDirectory(File dir, String packageName, List<Class<?>> classList) throws ClassNotFoundException {
        if (!dir.exists() || !dir.isDirectory()) return;
        File[] files = dir.listFiles();
        if (files == null) return;

        for (File file : files) {
            if (file.isDirectory()) {
                scanFileSystemDirectory(file, packageName + "." + file.getName(), classList);
            } else if (file.getName().endsWith(".class")) {
                String className = packageName + "." + file.getName().substring(0, file.getName().length() - 6);
                classList.add(Class.forName(className));
            }
        }
    }

    private static void scanJarFile(JarURLConnection conn, String packagePath, String packageName, List<Class<?>> classList) throws IOException, ClassNotFoundException {
        try (JarFile jarFile = conn.getJarFile()) {
            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                String entryName = entry.getName();
                // 过滤指定包下的.class文件,排除内部类(可根据需求调整)
                if (entryName.startsWith(packagePath) && entryName.endsWith(".class") && !entryName.contains("$")) {
                    String className = entryName.replace('/', '.').substring(0, entryName.length() - 6);
                    classList.add(Class.forName(className));
                }
            }
        }
    }
}

使用示例

public class Main {
    public static void main(String[] args) throws Exception {
        // 扫描java.util包下的所有类
        List<Class<?>> classes = PackageScanner.scanClasses("java.util");
        for (Class<?> cls : classes) {
            System.out.println("找到类:" + cls.getName());
        }
    }
}

注意事项

  • 该方法会加载所有找到的类,可能带来一定性能开销,建议按需使用。
  • 对于JDK11的模块化环境(模块路径下的模块),需要额外处理jrt协议的资源,可扩展上述代码的协议分支。
  • 内部类(文件名带$)默认被排除,可根据需求修改过滤条件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 05:43:46