Могу ли я сделать это с отражением или что-то в этом роде?
Как я могу получить список всех реализаций интерфейса программно в Java?
Ответ 1
Я искал некоторое время, и, кажется, есть разные подходы, вот резюме:
-  Библиотека отражений довольно популярна, если вы не возражаете против добавления зависимости. Это будет выглядеть так: 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как ServiceProviderInterface (SPI) и объявить его реализации. Вы делаете это путем создания файла в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;Обратите внимание, что только пакеты, которые известны ClassLoader в то время, будут загружены вызовом Package.getPackages().
Кроме того, существуют другие подходы, основанные на URLClassLoader, которые всегда будут ограничены классами, которые уже были загружены, если только вы не выполните поиск по каталогу.
Ответ 2
Что сказал Эриксон, но если вы все еще хотите это сделать, взгляните на " Размышления". Со своей страницы:
Используя Reflections, вы можете запросить ваши метаданные для:
- получить все подтипы некоторого типа
- получить аннотации всех типов с некоторой аннотацией
- получить аннотации для всех типов, включая сопоставление параметров аннотации
- получить аннотации всех методов с некоторыми
Ответ 3
В общем, это дорого делать. Чтобы использовать отражение, класс должен быть загружен. Если вы хотите загрузить каждый класс, доступный на пути к классам, это займет время и память, и не рекомендуется.
Если вы хотите избежать этого, вам нужно будет реализовать собственный анализатор файлов классов, который работал бы более эффективно, чем рефлексия. В этом подходе может помочь библиотека разработки байт-кода.
 Механизм Service Provider - это обычное средство для перечисления реализаций подключаемой службы. Используйте  ServiceLoader в Java 6 или реализуйте свой собственный в более ранних версиях. Я привел пример в другом ответе.
Ответ 4
У 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;
}
Ответ 5
Да, первым шагом является определение "всех" классов, о которых вы заботитесь. Если у вас уже есть эта информация, вы можете перечислить каждую из них и использовать instanceof для проверки отношения. Связанная статья находится здесь: http://www.javaworld.com/javaworld/javatips/jw-javatip113.html
Ответ 6
Что эриксон сказал лучше всего. Вот связанный вопрос и ответ нить - http://www.velocityreviews.com/forums/t137693-find-all-implementing-classes-in-classpath.html
Библиотека Apache BCEL позволяет вам читать классы без их загрузки. Я считаю, что это будет быстрее, потому что вы сможете пропустить этап проверки. Другая проблема с загрузкой всех классов с использованием загрузчика классов заключается в том, что вы будете испытывать огромное влияние на память, а также непреднамеренно запускать любые статические блоки кода, которые вы, вероятно, не хотите делать.
Ссылка на библиотеку Apache BCEL - http://jakarta.apache.org/bcel/
Ответ 7
С 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
}
Ответ 8
Кроме того, если вы пишете плагин IDE (где то, что вы пытаетесь сделать, является относительно распространенным), тогда среда IDE обычно предлагает более эффективные способы доступа к иерархии классов текущего состояния кода пользователя.
Ответ 9
Я столкнулся с той же проблемой. Мое решение состояло в том, чтобы использовать рефлексию для изучения всех методов класса ObjectFactory, исключая те методы, которые не были createXXX(), возвращающие экземпляр одного из моих связанных POJO. Каждый обнаруженный класс добавляется в массив Class [], который затем передается в экземплярный вызов JAXBContext. Это хорошо работает, нужно только загрузить класс ObjectFactory, который все равно понадобился. Мне нужно только поддерживать класс ObjectFactory, задачу, выполняемую вручную (в моем случае, потому что я начал с POJO и использовал схему), или может быть сгенерирован по необходимости xjc. В любом случае, он эффективен, прост и эффективен.
Ответ 10
Новая версия @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();
    }   
}
Ответ 11
Самый надежный механизм для перечисления всех классов, которые реализуют данный интерфейс, в настоящее время 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
    }
}
