Ahm*_*any 43
我一直在寻找,似乎有不同的方法,这里是一个总结:
如果您不介意添加依赖项,则反射库非常受欢迎.它看起来像这样:
Reflections reflections = new Reflections("firstdeveloper.examples.reflections");
Set<Class<? extends Pet>> classes = reflections.getSubTypesOf(Pet.class);
Run Code Online (Sandbox Code Playgroud)ServiceLoader(根据erickson的回答)它看起来像这样:
ServiceLoader<Pet> loader = ServiceLoader.load(Pet.class);
for (Pet implClass : loader) {
System.out.println(implClass.getClass().getSimpleName()); // prints Dog, Cat
}
Run Code Online (Sandbox Code Playgroud)
请注意,要使其工作,您需要定义Pet
为ServiceProviderInterface(SPI)并声明其实现.你通过resources/META-INF/services
使用名称创建一个文件examples.reflections.Pet
并声明其中的所有实现来Pet
做到这一点
examples.reflections.Dog
examples.reflections.Cat
Run Code Online (Sandbox Code Playgroud)包级注释.这是一个例子:
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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
和注释定义:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PACKAGE)
public @interface MyPackageAnnotation {
Class<?>[] implementationsOfPet() default {};
}
Run Code Online (Sandbox Code Playgroud)
并且您必须package-info.java
在该包内命名的文件中声明包级注释.这里是样本内容:
@MyPackageAnnotation(implementationsOfPet = {Dog.class, Cat.class})
package examples.reflections;
Run Code Online (Sandbox Code Playgroud)
请注意,只有当时ClassLoader已知的包才会被调用加载Package.getPackages()
.
此外,还有其他基于URLClassLoader的方法,它们将始终限于已经加载的类,除非您进行基于目录的搜索.
eri*_*son 25
一般来说,这样做很昂贵.要使用反射,必须加载该类.如果要加载类路径上可用的每个类,则需要时间和内存,不建议使用.
如果你想避免这种情况,你需要实现自己的类文件解析器,它可以更有效地运行,而不是反射.字节码工程库可以帮助这种方法.
所述服务提供商机构是枚举一个可插入的服务的实现中的常规手段.使用ServiceLoader
Java 6,或在早期版本中实现自己的.我在另一个答案中提供了一个例子.
kay*_*e99 13
Spring有一个非常简单的方法来实现这个:
public interface ITask {
void doStuff();
}
@Component
public class MyTask implements ITask {
public void doStuff(){}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以自动装配一个类型列表,ITask
Spring将用所有实现填充它:
@Service
public class TaskService {
@Autowired
private List<ITask> tasks;
}
Run Code Online (Sandbox Code Playgroud)
列出实现给定接口的所有类的最强大的机制目前是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
}
}
Run Code Online (Sandbox Code Playgroud)
使用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
}
Run Code Online (Sandbox Code Playgroud)
是的,第一步是确定您关心的“所有”类。如果您已经拥有此信息,则可以枚举它们中的每一个并使用instanceof来验证关系。相关文章在这里:https://web.archive.org/web/20100226233915/www.javaworld.com/javaworld/javatips/jw-javatip113.html