如何在Java中找到给定类的所有子类?

如何在Java中找到给定类的所有子类?,java,class,interface,subclass,Java,Class,Interface,Subclass,如何在Java中查找给定类的所有子类(或给定接口的所有实现者)? 到目前为止,我有一种方法可以做到这一点,但我发现它效率很低(至少可以这么说)。 方法是: 获取类路径上存在的所有类名的列表 加载每个类并测试它是否是所需类或接口的子类或实现者 在Eclipse中,有一个很好的特性称为类型层次结构,它能够非常有效地显示这一点。 一个人是如何以编程的方式去做的?除了你所描述的,没有其他方法可以做。想一想,如果不扫描类路径上的每个类,怎么知道哪些类扩展了ClassX Eclipse只能在看似“有效”的时

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

  • 获取类路径上存在的所有类名的列表
  • 加载每个类并测试它是否是所需类或接口的子类或实现者
  • 在Eclipse中,有一个很好的特性称为类型层次结构,它能够非常有效地显示这一点。
    一个人是如何以编程的方式去做的?

    除了你所描述的,没有其他方法可以做。想一想,如果不扫描类路径上的每个类,怎么知道哪些类扩展了ClassX


    Eclipse只能在看似“有效”的时间内告诉您有关超类和子类的信息,因为它已经在您按下“在类型层次结构中显示”按钮时加载了所有类型数据(因为它不断编译您的类,了解类路径上的所有信息,等等).

    仅使用内置Java反射API是不可能做到这一点的

    存在一个对类路径进行必要扫描和索引的项目,以便您可以访问此信息

    Java运行时元数据分析,以Scannotations为精神

    反射扫描您的类路径,索引元数据,允许您在运行时查询它,并且可以为项目中的许多模块保存和收集该信息。 使用反射,您可以查询元数据:

    • 获取某些类型的所有子类型
    • 使用一些注释获取所有类型的注释
    • 获取使用某些注释注释的所有类型,包括注释参数匹配
    • 让所有的方法都带有一些注释

    (免责声明:我没有使用它,但项目的描述似乎完全符合您的需要。)

    还应该注意,这当然只会找到当前类路径上存在的所有子类。这可能是你目前正在看的,你有可能考虑过这一点,但是如果你在任何时候发布了一个非<代码>最终的<代码>类到野生(对于不同级别的“野生”),那么其他人编写了自己不知道的子类是完全可行的。
    因此,如果你碰巧想看到所有的子类,因为你想做一个改变,并且想看看它是如何影响子类的行为的,那么记住你看不到的子类。理想情况下,所有非私有方法以及类本身都应该有良好的文档记录;根据本文档进行更改,而不更改方法/非私有字段的语义,并且您的更改应向后兼容,至少对于遵循您的超类定义的任何子类。

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

    您之所以看到实现与Eclipse之间的差异,是因为您每次都扫描,而Eclipse(和其他工具)只扫描一次(在大多数项目加载期间)然后创建一个索引。下次您请求数据时,它不会再次扫描,而是查看索引。

    使用纯Java扫描类并不容易

    spring框架提供了一个名为的类,它可以满足您的需要

    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
    }
    
    ClassPathScanningCandidateComponentProvider=新的ClassPathScanningCandidateComponentProvider(false);
    addIncludeFilter(新的AssignableTypeFilter(MyClass.class));
    //在org.example.package中扫描
    Set components=provider.findCandidateComponents(“org/example/package”);
    用于(BeanDefinition组件:组件)
    {
    Class cls=Class.forName(component.getBeanClassName());
    //使用找到的类cls
    }
    

    这种方法还有一个额外的好处,就是使用字节码分析器来查找候选类,这意味着它不会加载它扫描的所有类。

    我知道我参加这次聚会晚了几年,但我在试图解决同样的问题时遇到了这个问题。如果你正在编写Eclipse p,你可以通过编程方式使用Eclipse的内部搜索lugin(并因此利用其缓存等)查找实现接口的类。以下是我(非常粗略)的第一部分:

      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();
        }
      }
    
    受保护的void listImplementingClasses(字符串iface)引发CoreException
    {
    最终项目=;
    尝试
    {
    最终IType ifaceType=project.findType(iface);
    最终搜索模式ifacePattern=SearchPattern.createPattern(ifaceType,IJavaSearchConstants.IMPLEMENTORS);
    最终IJavaSearchScope范围=SearchEngine.createWorkspaceScope();
    最终搜索引擎SearchEngine=新搜索引擎();
    最终LinkedList结果=新建LinkedList();
    searchEngine.search(ifacePattern,
    新的SearchParticipant[]{SearchEngine.getDefaultSearchParticipant()},作用域,新的SearchRequestor(){
    @凌驾
    public void acceptSearchMatch(SearchMatch匹配)引发CoreException异常
    {
    结果。添加(匹配);
    }
    },新的IProgressMonitor(){
    @凌驾
    公共void起始任务(字符串名称,整数totalWork)
    {
    }
    @凌驾
    公众假期结束()
    {
    系统输出打印项次(结果);
    }
    @凌驾
    公共工程(双重工程)
    {
    }
    @凌驾
    公共布尔值已取消()
    {
    返回false;
    }
    @凌驾
    公共无效集合已取消(布尔值)
    {
    }
    @凌驾
    public void setTaskName(字符串名称)
    {
    }
    @凌驾
    普布利
    
    javadoc -d build -doclet com.example.ObjectListDoclet -sourcepath java/src -subpackages com.example
    
    <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;
            }
        }
    }
    
    for(PojoClass pojoClass : PojoClassFactory.enumerateClassesByExtendingType(packageRoot, Superclass.class, null)) {
        System.out.println(pojoClass.getClazz());
    }
    
    Reflections reflections = new Reflections("my.project");
    Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);
    
    package com.example;
    
    public interface Example {
        public String getStr();
    }
    
    package com.example;
    
    public class ExampleImpl implements Example {
        public String getStr() {
            return "ExampleImpl's string.";
        }
    }
    
    ServiceLoader<Example> loader = ServiceLoader.load(Example.class)
    for (Example example : loader) {
        System.out.println(example.getStr());
    }
    
    // Prints "ExampleImpl's string.", plus whatever is returned
    // by other declared implementations of com.example.Example.
    
    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());
            }
        }
    }
    
        Reflections reflections = new Reflections("my.project.prefix");
        System.out.println(reflections.getSubTypesOf(A.class)));
    
    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;
    }