当前位置:  开发笔记 > 编程语言 > 正文

查找实现接口的Java类

如何解决《查找实现接口的Java类》经验,为你挑选了8个好方法。

前段时间,我遇到了一段代码,它使用了一些标准的Java功能来定位实现给定接口的类.我知道函数隐藏在某些非逻辑位置,但它们可以用于其他类,因为包含的名称是隐含的.那时我不需要它,所以我忘了它,但现在我做了,我似乎无法再找到这些功能.这些功能在哪里可以找到?

编辑:我不是在寻找任何IDE函数或任何东西,而是可以在Java应用程序中执行的东西.



1> Brian Clappe..:

不久之前,我整理了一个包,用于做你想做的事情,等等.(我需要它用于我正在编写的实用程序).它使用ASM库.您可以使用反射,但ASM表现更好.

我将我的包放在我网站上的开源库中.该库位于:http://software.clapper.org/javautil/.您想从使用ClassFinder类开始.

我为它编写的实用程序是一个RSS阅读器,我仍然每天使用它,所以代码确实倾向于运用.我使用ClassFinder来支持RSS阅读器中的插件API; 在启动时,它在几个目录树中查找包含实现特定接口的类的jar和类文件.它比你想象的要快得多.

该库是BSD许可的,因此您可以安全地将其与您的代码捆绑在一起.来源可用.

如果这对你有用,请自己帮忙.

更新:如果您正在使用Scala,您可能会发现此库对Scala更友好.


这应该.如果没有,我需要解决它...

2> 小智..:

春天可以为你做到这一点......

BeanDefinitionRegistry bdr = new SimpleBeanDefinitionRegistry();
ClassPathBeanDefinitionScanner s = new ClassPathBeanDefinitionScanner(bdr);

TypeFilter tf = new AssignableTypeFilter(CLASS_YOU_WANT.class);
s.addIncludeFilter(tf);
s.scan("package.you.want1", "package.you.want2");       
String[] beans = bdr.getBeanDefinitionNames();

注意如果您想要正确的结果,TypeFilter很重要!您也可以在此处使用排除过滤器.

Scanner可以在spring-context jar中找到,spring-beans中的注册表,类型过滤器是spring-core.


您可能希望添加`s.setIncludeAnnotationConfig(false);`来过滤Spring自己的类.
`s.resetFilters(false);`将删除默认的Spring过滤器,它将包含带有@ Component,@ Service和其他一些注释的所有类放入结果集中.

3> 小智..:

我非常喜欢这样做的反射库.

它提供了大量不同类型的扫描仪(的getTypesAnnotatedWith,getSubTypesOf等等),它是死的简单写或扩展自己.



4> erickson..:

你正在谈论的代码听起来ServiceLoader,这是在Java 6中推出了支持,因为已定义功能的Java 1.3或更早版本.出于性能原因,这是在运行时查找接口实现的推荐方法; 如果您需要在旧版本的Java中支持此功能,我希望您会发现我的实现很有帮助.

在早期版本的Java中有几个这样的实现,但是在Sun包中,而不是在核心API中(我认为ImageIO内部有一些类来执行此操作).由于代码很简单,我建议您提供自己的实现,而不是依赖于可能会发生变化的非标准Sun代码.


AFAI理解它,海报确实想要任意接口,所以ServiceLoader可能没有帮助.
如果你想自动生成META-INF服务,请查看Kohsuke的MetaInfServices http://weblogs.java.net/blog/kohsuke/archive/2009/03/my_project_of_t.html

5> Adam Gent..:

包级别注释

我知道很久以前这个问题已经得到解答了,但是这个问题的另一个解决方案是使用Package Level Annotations.

虽然很难找到JVM中的所有类,但实际上很容易浏览包层次结构.

Package[] ps = Package.getPackages();
for (Package p : ps) {
  MyAno a = p.getAnnotation(MyAno.class)
  // Recursively descend
}

然后让你的注释有一个Class数组的参数.然后在package-info.java中为特定包放置MyAno.

如果人们有兴趣,我会添加更多细节(代码),但最有可能得到这个想法.

MetaInf服务加载器

要添加到@erickson答案,您还可以使用服务加载器方法.Kohsuke有一种很棒的方法来生成服务加载器方法所需的META-INF内容:

http://weblogs.java.net/blog/kohsuke/archive/2009/03/my_project_of_t.html


注意:并非所有软件包都在运行时可用.见[这里](http://stackoverflow.com/questions/1816730/is-there-a-way-to-force-a-classloader-to-load-a-package-even-if-none-of-its -clas)了解更多信息.
请添加更多代码以显示注释示例。已经给+1了。

6> 小智..:

您还可以使用可扩展组件扫描程序(extcos:http://sf.net/projects/extcos )并搜索所有实现如下界面的类:

Set> classes = new HashSet>();

ComponentScanner scanner = new ComponentScanner();
scanner.getClasses(new ComponentQuery() {
    @Override
    protected void query() {
        select().
        from("my.package1", "my.package2").
        andStore(thoseImplementing(MyInterface.class).into(classes)).
        returning(none());
    }
});

这适用于文件系统上的类,在jar中,甚至适用于JBoss虚拟文件系统上的类.它进一步设计用于独立应用程序以及任何Web或应用程序容器.



7> Michael Borg..:

完全一般,这个功能是不可能的.Java ClassLoader机制仅保证能够请求具有特定名称的类(包括pacakge),并且ClassLoader可以提供类,或者它可以声明它不知道该类.

可以(并且经常)从远程服务器加载类,甚至可以在运行中构建它们; 编写一个ClassLoader并不难,它返回一个有效的类,为你从中提出的任何名称实现给定的接口; 实现该接口的类的列表的长度将是无限的.

实际上,最常见的情况是URLClassLoader在文件系统目录和JAR文件列表中查找类.因此,您需要获取URLClassLoader,然后遍历这些目录和存档,并为您在其中找到的每个类文件,请求相应的Class对象并查看其getInterfaces()方法的返回.



8> Neil Coffey..:

显然,Class.isAssignableFrom()会告诉您单个类是否实现给定的接口.那么问题是获取要测试的类列表.

据我所知,Java没有直接的方式向类加载器询问" 可能加载的类列表".所以你必须通过遍历可见的jar来自己做,调用Class.forName()来加载类,然后测试它.

但是,如果您只想知道实际加载的那些实现给定接口的类,那么它会更容易一些:

通过Java Instrumentation框架,您可以调用Instrumentation.getAllLoadedClasses()

通过反射,您可以查询给定ClassLoader 的ClassLoader.classes字段.

如果您使用检测技术,那么(如链接中所述)会发生什么是在JVM启动时调用"代理"类并传递Instrumentation对象.此时,您可能希望在静态字段中"将其保存以供日后使用",然后让主应用程序代码稍后调用它以获取已加载类的列表.

推荐阅读
小妖694_807
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有