如何在Java中找到给定类的所有子类(或给定接口的所有实现者)? 到目前为止,我有一个方法来做到这一点,但我发现它相当低效(至少可以说)。 方法是:
获取类路径上存在的所有类名的列表 加载每个类并测试它是否是所需类或接口的子类或实现者
在Eclipse中,有一个很好的特性叫做类型层次结构,它能够非常有效地显示这一点。 如何以编程的方式进行呢?
如何在Java中找到给定类的所有子类(或给定接口的所有实现者)? 到目前为止,我有一个方法来做到这一点,但我发现它相当低效(至少可以说)。 方法是:
获取类路径上存在的所有类名的列表 加载每个类并测试它是否是所需类或接口的子类或实现者
在Eclipse中,有一个很好的特性叫做类型层次结构,它能够非常有效地显示这一点。 如何以编程的方式进行呢?
当前回答
你可以使用org。然后,创建一个reflections类的对象。使用此对象,您可以获得给定类的所有子类的列表。 https://www.javadoc.io/doc/org.reflections/reflections/0.9.10/org/reflections/Reflections.html
Reflections reflections = new Reflections("my.project.prefix");
System.out.println(reflections.getSubTypesOf(A.class)));
其他回答
几年前我就这样做了。最可靠的方法(即使用官方Java api,没有外部依赖)是编写一个自定义doclet来生成一个可以在运行时读取的列表。
你可以像这样从命令行运行它:
javadoc -d build -doclet com.example.ObjectListDoclet -sourcepath java/src -subpackages com.example
或者像这样从ant运行它:
<javadoc sourcepath="${src}" packagenames="*" >
<doclet name="com.example.ObjectListDoclet" path="${build}"/>
</javadoc>
下面是基本代码:
public final class ObjectListDoclet {
public static final String TOP_CLASS_NAME = "com.example.MyClass";
/** Doclet entry point. */
public static boolean start(RootDoc root) throws Exception {
try {
ClassDoc topClassDoc = root.classNamed(TOP_CLASS_NAME);
for (ClassDoc classDoc : root.classes()) {
if (classDoc.subclassOf(topClassDoc)) {
System.out.println(classDoc);
}
}
return true;
}
catch (Exception ex) {
ex.printStackTrace();
return false;
}
}
}
为了简单起见,我删除了命令行参数解析,并将其写入System。Out而不是file。
不要忘记,为类生成的Javadoc将包括一个已知子类列表(对于接口,包括已知实现类)。
我使用了一个反射库,它扫描所有子类的类路径:https://github.com/ronmamo/reflections
这是如何做到的:
Reflections reflections = new Reflections("my.project");
Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);
还要注意的是,这当然只能找到当前类路径中存在的所有子类。想必这对于你目前所看到的是可以的,而且你也有可能考虑过这一点,但如果你在任何时候发布了一个非最终类(对于不同程度的“狂野”),那么其他人已经编写了他们自己的子类,而你不知道这是完全可行的。
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.
用纯Java扫描类并不容易。
spring框架提供了一个名为ClassPathScanningCandidateComponentProvider的类,它可以满足您的需要。下面的示例将在包org.example.package中找到MyClass的所有子类
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AssignableTypeFilter(MyClass.class));
// scan in org.example.package
Set<BeanDefinition> components = provider.findCandidateComponents("org/example/package");
for (BeanDefinition component : components)
{
Class cls = Class.forName(component.getBeanClassName());
// use class cls found
}
该方法还有一个额外的好处,就是使用字节码分析器来查找候选类,这意味着它不会加载所扫描的所有类。