如何在java中以编程方式获得接口的所有实现的列表?

rryofs0p  于 2021-06-29  发布在  Java
关注(0)|答案(11)|浏览(346)

**结束。**此问题不符合堆栈溢出准则。它目前不接受答案。
**想改进这个问题吗?**更新问题,使其成为堆栈溢出的主题。

两个月前关门了。
改进这个问题
我可以用倒影之类的方法吗?

s3fp2yjn

s3fp2yjn1#

一般来说,这样做很昂贵。要使用反射,必须加载类。如果您想加载类路径上所有可用的类,这将花费时间和内存,不建议这样做。
如果您想避免这种情况,您需要实现自己的类文件解析器,它可以更有效地运行,而不是反射。字节码工程库可能有助于这种方法。
服务提供者机制是枚举可插拔服务实现的传统方法,随着Java9中jigsaw项目(模块)的引入,它变得更加成熟。使用 ServiceLoader 或者在早期版本中实现自己的。我在另一个答案中提供了一个例子。

au9on6nz

au9on6nz2#

是的,第一步是确定“所有”你关心的类。如果您已经有了这些信息,您可以枚举它们中的每一个,并使用instanceof验证关系。相关文章如下:https://web.archive.org/web/20100226233915/www.javaworld.com/javaworld/javatips/jw-javatip113.html

3zwtqj6y

3zwtqj6y3#

就像埃里克森说的,但如果你还想这么做,那就看看反射。从他们的页面:
使用反射,您可以查询元数据:
获取某类型的所有子类型
使用一些注解对所有类型进行注解
使用一些注解获取所有类型的注解,包括注解参数匹配
使用一些

yrefmtwq

yrefmtwq4#

另外,如果您正在编写一个ide插件(您尝试做的是比较常见的),那么ide通常会为您提供更有效的方法来访问用户代码当前状态的类层次结构。

cfh9epnr

cfh9epnr5#

classgraph非常简单:
查找的实现的groovy代码 my.package.MyInterface :

@Grab('io.github.classgraph:classgraph:4.6.18')
import io.github.classgraph.*
new ClassGraph().enableClassInfo().scan().withCloseable { scanResult ->
    scanResult.getClassesImplementing('my.package.MyInterface').findAll{!it.abstract}*.name
}
dfuffjeb

dfuffjeb6#

一个新版本的@kaybee99的答案,但现在返回用户的问题:实现。。。
spring有一个非常简单的方法来实现这一点:

public interface ITask {
    void doStuff();
    default ITask getImplementation() {
       return this;
    }

}

@Component
public class MyTask implements ITask {
   public void doStuff(){}
}

然后可以自动关联类型列表 ITask spring将用所有实现填充它:

@Service
public class TaskService {

    @Autowired(required = false)
    private List<ITask> tasks;

    if ( tasks != null)
    for (ITask<?> taskImpl: tasks) {
        taskImpl.doStuff();
    }   
}
uqjltbpv

uqjltbpv7#

列出实现给定接口的所有类的最健壮的机制目前是classgraph,因为它处理尽可能广泛的类路径规范机制数组,包括新的jpms模块系统(我是作者。)

try (ScanResult scanResult = new ClassGraph().whitelistPackages("x.y.z")
        .enableClassInfo().scan()) {
    for (ClassInfo ci : scanResult.getClassesImplementing("x.y.z.SomeInterface")) {
        foundImplementingClass(ci);  // Do something with the ClassInfo object
    }
}
j9per5c4

j9per5c48#

埃里克森说的最好。下面是一个相关的问答线索-http://www.velocityreviews.com/forums/t137693-find-all-implementing-classes-in-classpath.html
apachebcel库允许您在不加载类的情况下读取类。我相信它会更快,因为你应该能够跳过验证步骤。使用类加载器加载所有类的另一个问题是,您将遭受巨大的内存影响,并且会无意中运行任何您可能不想执行的静态代码块。
apache bcel库链接-http://jakarta.apache.org/bcel/

6l7fqoea

6l7fqoea9#

spring有一个非常简单的方法来实现这一点:

public interface ITask {
    void doStuff();
}

@Component
public class MyTask implements ITask {
   public void doStuff(){}
}

然后可以自动关联类型列表 ITask spring将用所有实现填充它:

@Service
public class TaskService {

    @Autowired
    private List<ITask> tasks;
}
qyuhtwio

qyuhtwio10#

我已经搜索了一段时间,似乎有不同的方法,这里是一个总结:
如果您不介意添加依赖项,那么反射库非常流行。它看起来是这样的:

Reflections reflections = new Reflections("firstdeveloper.examples.reflections");
Set<Class<? extends Pet>> classes = reflections.getSubTypesOf(Pet.class);

serviceloader(根据erickson的回答),它看起来是这样的:

ServiceLoader<Pet> loader = ServiceLoader.load(Pet.class);
for (Pet implClass : loader) {
    System.out.println(implClass.getClass().getSimpleName()); // prints Dog, Cat
}

请注意,要使其工作,您需要定义 Pet 并声明其实现。您可以通过在中创建一个文件来实现这一点 resources/META-INF/services 有名字吗 examples.reflections.Pet 并声明 Pet 在里面

examples.reflections.Dog
examples.reflections.Cat

包级别注解。举个例子:

Package[] packages = Package.getPackages();
for (Package p : packages) {
    MyPackageAnnotation annotation = p.getAnnotation(MyPackageAnnotation.class);
    if (annotation != null) {
        Class<?>[]  implementations = annotation.implementationsOfPet();
        for (Class<?> impl : implementations) {
            System.out.println(impl.getSimpleName());
        }
    }
}

以及注解定义:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PACKAGE)
public @interface MyPackageAnnotation {
    Class<?>[] implementationsOfPet() default {};
}

并且必须在名为 package-info.java 在包裹里。以下是示例内容:

@MyPackageAnnotation(implementationsOfPet = {Dog.class, Cat.class})
package examples.reflections;

请注意,只有类加载器当时知道的包才会通过调用 Package.getPackages() .
此外,还有其他基于urlclassloader的方法,除非您执行基于目录的搜索,否则这些方法将始终限于已加载的类。

aydmsdu9

aydmsdu911#

我也遇到了同样的问题。我的解决方案是使用反射来检查objectfactory类中的所有方法,消除那些不是create()方法的方法,这些方法返回一个绑定pojo的示例。这样发现的每个类都被添加到一个class[]数组中,然后该数组被传递给jaxbcontext示例化调用。这执行得很好,只需要加载objectfactory类,这是无论如何都需要的。我只需要维护objectfactory类,这个任务可以手工执行(在我的例子中,因为我从pojo开始使用schemagen),也可以根据xjc的需要生成。无论哪种方式,它都是高效、简单和有效的。

相关问题