是否有可能找到给定包中的所有类或接口?(快速看了一下e.g. Package,似乎没有。)


当前回答

如果您不使用任何动态类加载器,您可以搜索类路径,并为每个条目搜索目录或JAR文件。

其他回答

这是不可能的,因为包中的所有类都可能不会被加载,而你总是知道一个类的包。

我刚写了一个util类,里面包含了测试方法,大家可以检查一下~

IteratePackageUtil.java:

package eric.j2se.reflect;

import java.util.Set;

import org.reflections.Reflections;
import org.reflections.scanners.ResourcesScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;

/**
 * an util to iterate class in a package,
 * 
 * @author eric
 * @date Dec 10, 2013 12:36:46 AM
 */
public class IteratePackageUtil {
    /**
     * <p>
     * Get set of all class in a specified package recursively. this only support lib
     * </p>
     * <p>
     * class of sub package will be included, inner class will be included,
     * </p>
     * <p>
     * could load class that use the same classloader of current class, can't load system packages,
     * </p>
     * 
     * @param pkg
     *            path of a package
     * @return
     */
    public static Set<Class<? extends Object>> getClazzSet(String pkg) {
        // prepare reflection, include direct subclass of Object.class
        Reflections reflections = new Reflections(new ConfigurationBuilder().setScanners(new SubTypesScanner(false), new ResourcesScanner())
                .setUrls(ClasspathHelper.forClassLoader(ClasspathHelper.classLoaders(new ClassLoader[0])))
                .filterInputsBy(new FilterBuilder().includePackage(pkg)));

        return reflections.getSubTypesOf(Object.class);
    }

    public static void test() {
        String pkg = "org.apache.tomcat.util";

        Set<Class<? extends Object>> clazzSet = getClazzSet(pkg);
        for (Class<? extends Object> clazz : clazzSet) {
            System.out.println(clazz.getName());
        }
    }

    public static void main(String[] args) {
        test();
    }
}

这是非常有可能的,但是如果没有像Reflections这样的附加库,这就很难了。 这很困难,因为你没有完整的工具来获取类名。 然后,我取ClassFinder类的代码:

package play.util;

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

/**
 * Created by LINKOR on 26.05.2017 in 15:12.
 * Date: 2017.05.26
 */
public class FileClassFinder {
private JarFile file;
private boolean trouble;
public FileClassFinder(String filePath) {
    try {
        file = new JarFile(filePath);
    } catch (IOException e) {
        trouble = true;
    }
}

public List<String> findClasses(String pkg) {
    ArrayList<String> classes = new ArrayList<>();
    Enumeration<JarEntry> entries = file.entries();
    while (entries.hasMoreElements()) {
        JarEntry cls = entries.nextElement();
        if (!cls.isDirectory()) {
            String fileName = cls.getName();
            String className = fileName.replaceAll("/",         ".").replaceAll(File.pathSeparator, ".").substring(0, fileName.lastIndexOf('.'));
            if (className.startsWith(pkg)) classes.add(className.substring(pkg.length() + 1));
        }
    }
    return classes;
}
}

目前列出给定包中所有类的最健壮的机制是ClassGraph,因为它处理尽可能广泛的类路径规范机制,包括新的JPMS模块系统。(我是作者。)

List<String> classNames = new ArrayList<>();
try (ScanResult scanResult = new ClassGraph().acceptPackages("my.package")
        .enableClassInfo().scan()) {
    classNames.addAll(scanResult.getAllClasses().getNames());
}

由于类装入器的动态特性,这是不可能的。类装入器不需要告诉VM它可以提供哪些类,相反,它们只是提交类请求,并且必须返回类或抛出异常。

但是,如果您编写自己的类装入器,或者检查类路径和它的jar,就有可能找到这些信息。不过,这将通过文件系统操作,而不是反射。甚至可能有一些库可以帮助你做到这一点。

如果有远程生成或交付的类,您将无法发现这些类。

通常的方法是在某个文件中注册需要访问的类,或者在不同的类中引用它们。或者在命名时使用惯例。

附录:反射库将允许您在当前类路径中查找类。它可以用来获取包中的所有类:

 Reflections reflections = new Reflections("my.project.prefix");

 Set<Class<? extends Object>> allClasses = 
     reflections.getSubTypesOf(Object.class);