如何在Java中尝试查找给定类(或给定接口的所有实现者)的所有子类?截至目前,我有一种方法可以做到这一点,但我觉得效率很低(至少可以说).方法是:
获取类路径上存在的所有类名的列表
加载每个类并测试它是否是所需类或接口的子类或实现者
在Eclipse中,有一个很好的功能叫做类型层次结构,可以非常有效地显示它.如何以编程方式进行操作?
使用纯Java扫描类并不容易.
spring框架提供了一个名为ClassPathScanningCandidateComponentProvider的类,它可以满足您的需求.以下示例将在包org.example.package中找到MyClass的所有子类
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); provider.addIncludeFilter(new AssignableTypeFilter(MyClass.class)); // scan in org.example.package Setcomponents = provider.findCandidateComponents("org/example/package"); for (BeanDefinition component : components) { Class cls = Class.forName(component.getBeanClassName()); // use class cls found }
此方法的另一个好处是使用字节码分析器来查找候选项,这意味着它不会加载它扫描的所有类.
除了你描述的内容之外别无他法.想一想 - 如何在不扫描类路径上的每个类的情况下知道什么类扩展ClassX?
Eclipse只能告诉你超级和子类似乎是一个"有效"的时间量,因为它已经在你按下"在类型层次结构中显示"按钮的位置加载了所有类型数据(因为它是不断编译你的类,了解类路径上的所有内容,等等.
仅使用内置的Java Reflections API无法做到这一点.
存在一个项目,它对您的类路径进行必要的扫描和索引,以便您可以访问此信息...
一种Java运行时元数据分析,本着Scannotations的精神
Reflections会扫描您的类路径,索引元数据,允许您在运行时查询它,并可以为项目中的许多模块保存和收集该信息.使用Reflections,您可以查询元数据:
获取某种类型的所有子类型
获取带有注释的所有类型注释
获取所有注释了一些注释的类型,包括注释参数匹配
得到所有用一些注释的方法
(免责声明:我没有使用它,但该项目的描述似乎完全符合您的需求.)
不要忘记,为类生成的Javadoc将包含已知子类的列表(以及接口,已知的实现类).
几年前我这样做了.执行此操作的最可靠方法(即使用官方Java API且无外部依赖项)是编写自定义doclet以生成可在运行时读取的列表.
您可以从命令行运行它,如下所示:
javadoc -d build -doclet com.example.ObjectListDoclet -sourcepath java/src -subpackages com.example
或者像这样从ant运行它:
这是基本代码:
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而不是文件.
我知道我参加这个聚会已经晚了几年,但是我试图解决同样的问题.您可以以编程方式使用Eclipse的内部搜索,如果您正在编写Eclipse插件(从而利用其缓存等),则可以查找实现接口的类.这是我(非常粗略)的第一次切割:
protected void listImplementingClasses( String iface ) throws CoreException { final IJavaProject project =; try { final IType ifaceType = project.findType( iface ); final SearchPattern ifacePattern = SearchPattern.createPattern( ifaceType, IJavaSearchConstants.IMPLEMENTORS ); final IJavaSearchScope scope = SearchEngine.createWorkspaceScope(); final SearchEngine searchEngine = new SearchEngine(); final LinkedList results = new LinkedList (); searchEngine.search( ifacePattern, new SearchParticipant[]{ SearchEngine.getDefaultSearchParticipant() }, scope, new SearchRequestor() { @Override public void acceptSearchMatch( SearchMatch match ) throws CoreException { results.add( match ); } }, new IProgressMonitor() { @Override public void beginTask( String name, int totalWork ) { } @Override public void done() { System.out.println( results ); } @Override public void internalWorked( double work ) { } @Override public boolean isCanceled() { return false; } @Override public void setCanceled( boolean value ) { } @Override public void setTaskName( String name ) { } @Override public void subTask( String name ) { } @Override public void worked( int work ) { } }); } catch( JavaModelException e ) { e.printStackTrace(); } }
到目前为止我看到的第一个问题是我只捕获直接实现接口的类,而不是所有的子类 - 但是一点点的递归从不会伤害任何人.
请记住其他答案中提到的限制,您也可以通过以下方式使用openpojoPojoClassFactory
(在Maven上可用):
for(PojoClass pojoClass : PojoClassFactory.enumerateClassesByExtendingType(packageRoot, Superclass.class, null)) { System.out.println(pojoClass.getClazz()); }
packageRoot
您希望搜索的包的根字符串在哪里(例如"com.mycompany"
,甚至只是"com"
),并且Superclass
是您的超类型(这也适用于接口).
试试ClassGraph.(免责声明,我是作者).ClassGraph支持在运行时或构建时扫描给定类的子类,但也支持更多.ClassGraph可以在内存中为类路径上的所有类或白名单包中的类构建整个类图(所有类,注释,方法,方法参数和字段)的抽象表示,然后您可以查询该类图你要.ClassGraph支持比任何其他扫描程序更多的类路径规范机制和类加载器,并且还可以与新的JPMS模块系统无缝协作,因此如果您将代码基于ClassGraph,您的代码将最大程度地可移植.请在此处查看API.