如何在Java中找到给定类的所有子类(或给定接口的所有实现者)? 到目前为止,我有一个方法来做到这一点,但我发现它相当低效(至少可以说)。 方法是:

获取类路径上存在的所有类名的列表 加载每个类并测试它是否是所需类或接口的子类或实现者

在Eclipse中,有一个很好的特性叫做类型层次结构,它能够非常有效地显示这一点。 如何以编程的方式进行呢?


当前回答

将它们添加到父类构造函数(this. getclass (). getname())内部的静态映射(或创建一个默认映射),但这将在运行时更新。如果可以选择延迟初始化,可以尝试这种方法。

其他回答

如果你想加载给定类在同一个包中的所有子类,你可以这样做:

public static List<Class> loadAllSubClasses(Class pClazz) throws IOException, ClassNotFoundException {
    ClassLoader classLoader = pClazz.getClassLoader();
    assert classLoader != null;
    String packageName = pClazz.getPackage().getName();
    String dirPath = packageName.replace(".", "/");
    Enumeration<URL> srcList = classLoader.getResources(dirPath);

    List<Class> subClassList = new ArrayList<>();
    while (srcList.hasMoreElements()) {
        File dirFile = new File(srcList.nextElement().getFile());
        File[] files = dirFile.listFiles();
        if (files != null) {
            for (File file : files) {
                String subClassName = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);
                if (! subClassName.equals(pClazz.getName())) {
                    subClassList.add(Class.forName(subClassName));
                }
            }
        }
    }

    return subClassList;
}

将它们添加到父类构造函数(this. getclass (). getname())内部的静态映射(或创建一个默认映射),但这将在运行时更新。如果可以选择延迟初始化,可以尝试这种方法。

我需要将此作为一个测试用例,以查看是否向代码中添加了新的类。这就是我所做的

final static File rootFolder = new File(SuperClass.class.getProtectionDomain().getCodeSource().getLocation().getPath());
private static ArrayList<String> files = new ArrayList<String>();
listFilesForFolder(rootFolder); 

@Test(timeout = 1000)
public void testNumberOfSubclasses(){
    ArrayList<String> listSubclasses = new ArrayList<>(files);
    listSubclasses.removeIf(s -> !s.contains("Superclass.class"));
    for(String subclass : listSubclasses){
        System.out.println(subclass);
    }
    assertTrue("You did not create a new subclass!", listSubclasses.size() >1);     
}

public static void listFilesForFolder(final File folder) {
    for (final File fileEntry : folder.listFiles()) {
        if (fileEntry.isDirectory()) {
            listFilesForFolder(fileEntry);
        } else {
            files.add(fileEntry.getName().toString());
        }
    }
}

您看到您的实现和Eclipse之间的区别的原因是您每次都扫描,而Eclipse(和其他工具)只扫描一次(大多数时候在项目加载期间)并创建索引。下次你请求数据时,它不再扫描,而是查看索引。

找到classpath中的所有类

public static List<String> getClasses() {
        URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
        List<String> classes = new ArrayList<>();
        for (URL url : urlClassLoader.getURLs()) {
            try {
                if (url.toURI().getScheme().equals("file")) {
                    File file = new File(url.toURI());
                    if (file.exists()) {
                        try {
                            if (file.isDirectory()) {
                                for (File listFile : FileUtils.listFiles(file, new String[]{"class"}, true)) {
                                    String classFile = listFile.getAbsolutePath().replace(file.getAbsolutePath(), "").replace(".class", "");
                                    if (classFile.startsWith(File.separator)) {
                                        classFile = classFile.substring(1);
                                    }
                                    classes.add(classFile.replace(File.separator, "."));
                                }
                            } else {
                                JarFile jarFile = new JarFile(file);
                                if (url.getFile().endsWith(".jar")) {
                                    Enumeration<JarEntry> entries = jarFile.entries();
                                    while (entries.hasMoreElements()) {
                                        JarEntry jarEntry = entries.nextElement();
                                        if (jarEntry.getName().endsWith(".class")) {
                                            classes.add(jarEntry.getName().replace(".class", "").replace("/", "."));
                                        }
                                    }
                                }
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
        }
        return classes;
    }