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

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

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


当前回答

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

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());
        }
    }
}

其他回答

不要忘记,为类生成的Javadoc将包括一个已知子类列表(对于接口,包括已知实现类)。

还要注意的是,这当然只能找到当前类路径中存在的所有子类。想必这对于你目前所看到的是可以的,而且你也有可能考虑过这一点,但如果你在任何时候发布了一个非最终类(对于不同程度的“狂野”),那么其他人已经编写了他们自己的子类,而你不知道这是完全可行的。

Thus if you happened to be wanting to see all subclasses because you want to make a change and are going to see how it affects subclasses' behaviour - then bear in mind the subclasses that you can't see. Ideally all of your non-private methods, and the class itself should be well-documented; make changes according to this documentation without changing the semantics of methods/non-private fields and your changes should be backwards-compatible, for any subclass that followed your definition of the superclass at least.

记住其他答案中提到的限制,你也可以以以下方式使用openpojo的PojoClassFactory(在Maven上可用):

for(PojoClass pojoClass : PojoClassFactory.enumerateClassesByExtendingType(packageRoot, Superclass.class, null)) {
    System.out.println(pojoClass.getClazz());
}

packageRoot是你想要搜索的包的根字符串。“com。mycompany”或者只是“com”),超类是你的超类型(这也适用于接口)。

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

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());
        }
    }
}

找到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;
    }