如何在Java中找到给定类的所有子类(或给定接口的所有实现者)? 到目前为止,我有一个方法来做到这一点,但我发现它相当低效(至少可以说)。 方法是:
获取类路径上存在的所有类名的列表 加载每个类并测试它是否是所需类或接口的子类或实现者
在Eclipse中,有一个很好的特性叫做类型层次结构,它能够非常有效地显示这一点。 如何以编程的方式进行呢?
如何在Java中找到给定类的所有子类(或给定接口的所有实现者)? 到目前为止,我有一个方法来做到这一点,但我发现它相当低效(至少可以说)。 方法是:
获取类路径上存在的所有类名的列表 加载每个类并测试它是否是所需类或接口的子类或实现者
在Eclipse中,有一个很好的特性叫做类型层次结构,它能够非常有效地显示这一点。 如何以编程的方式进行呢?
当前回答
记住其他答案中提到的限制,你也可以以以下方式使用openpojo的PojoClassFactory(在Maven上可用):
for(PojoClass pojoClass : PojoClassFactory.enumerateClassesByExtendingType(packageRoot, Superclass.class, null)) {
System.out.println(pojoClass.getClazz());
}
packageRoot是你想要搜索的包的根字符串。“com。mycompany”或者只是“com”),超类是你的超类型(这也适用于接口)。
其他回答
除了你所描述的,没有别的办法了。想想看——如果不扫描类路径上的每个类,如何知道哪些类扩展了ClassX ?
Eclipse只能在看起来“有效”的时间内告诉您关于父类和子类的信息,因为在您按下“显示在类型层次结构中”按钮时,它已经加载了所有类型数据(因为它一直在编译您的类,知道类路径上的所有内容,等等)。
将它们添加到父类构造函数(this. getclass (). getname())内部的静态映射(或创建一个默认映射),但这将在运行时更新。如果可以选择延迟初始化,可以尝试这种方法。
我知道我在这个派对上晚了几年,但我遇到这个问题是为了解决同样的问题。如果您正在编写Eclipse Plugin(从而利用它们的缓存等),您可以通过编程方式使用Eclipse的内部搜索来查找实现接口的类。这是我(非常粗糙的)第一次剪:
protected void listImplementingClasses( String iface ) throws CoreException
{
final IJavaProject project = <get your project here>;
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<SearchMatch> results = new LinkedList<SearchMatch>();
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();
}
}
到目前为止,我看到的第一个问题是,我只捕获直接实现接口的类,而不是它们的所有子类——但一点递归不会伤害任何人。
几年前我就这样做了。最可靠的方法(即使用官方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。
Try ClassGraph. (Disclaimer, I am the author). ClassGraph supports scanning for subclasses of a given class, either at runtime or at build time, but also much more. ClassGraph can build an abstract representation of the entire class graph (all classes, annotations, methods, method parameters, and fields) in memory, for all classes on the classpath, or for classes in selected packages, and you can query this class graph however you want. ClassGraph supports more classpath specification mechanisms and classloaders than any other scanner, and also works seamlessly with the new JPMS module system, so if you base your code on ClassGraph, your code will be maximally portable. See the API here.