Получить все классы, реализующие один и тот же интерфейс в Java [duplicate]

/**
 * Access a deep value inside a object 
 * Works by passing a path like "foo.bar", also works with nested arrays like "foo[0][1].baz"
 * @author Victor B. https://gist.github.com/victornpb/4c7882c1b9d36292308e
 * Unit tests: http://jsfiddle.net/Victornpb/0u1qygrh/
 */
function getDeepVal(obj, path) {
    if (typeof obj === "undefined" || obj === null) return;
    path = path.split(/[\.\[\]\"\']{1,2}/);
    for (var i = 0, l = path.length; i < l; i++) {
        if (path[i] === "") continue;
        obj = obj[path[i]];
        if (typeof obj === "undefined" || obj === null) return;
    }
    return obj;
}

Работает с

getDeepVal(obj,'foo.bar')
getDeepVal(obj,'foo.1.bar')
getDeepVal(obj,'foo[0].baz')
getDeepVal(obj,'foo[1][2]')
getDeepVal(obj,"foo['bar'].baz")
getDeepVal(obj,"foo['bar']['baz']")
getDeepVal(obj,"foo.bar.0.baz[1]['2']['w'].aaa[\"f\"].bb")
49
задан user2427 7 December 2008 в 05:52
поделиться

9 ответов

Что сказал erickson, но если вы все еще хотите это сделать, взгляните на Reflections . На своей странице:

Используя Reflections, вы можете запросить свои метаданные для:

  • получить все подтипы некоторого типа
  • получить все типы, аннотированные с некоторой аннотацией
  • получить все типы, аннотированные с некоторой аннотацией, включая параметры аннотации, соответствующие
  • , получить все методы, аннотированные с некоторыми
25
ответ дан Aldo 26 August 2018 в 21:32
поделиться
  • 1
    более конкретно: new Reflections("my.package").getSubTypesOf(MyInterface.class) – zapp 16 March 2013 в 15:12

В общем, это дорого. Чтобы использовать отражение, класс должен быть загружен. Если вы хотите загрузить каждый класс, доступный в пути к классам, это потребует времени и памяти и не рекомендуется.

Если вы хотите этого избежать, вам нужно будет реализовать собственный анализатор файлов классов, который работает более эффективно, вместо отражения.

Механизм поставщика поставщика услуг является обычным средством для перечисления реализаций подключаемой услуги. Используйте ServiceLoader в Java 6 или реализуйте свои собственные в более ранних версиях. Я представил пример в другом ответе.

20
ответ дан Community 26 August 2018 в 21:32
поделиться
  • 1
    К сожалению, для механизма поставщика услуг вам необходимо перечислить классы, которые могут быть в списке интересов в отдельном файле, что часто неосуществимо. – averasko 31 May 2015 в 15:41
  • 2
    Можно написать исходный код, реализующий интерфейс, его компиляцию и развертывание, но не обязательно включать текстовый файл с FQN реализации? Это редко, если вообще когда-либо, дело. Вряд ли «часто». – erickson 12 March 2017 в 17:45

Весна имеет довольно простой способ достичь этого:

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;
}
7
ответ дан kaybee99 26 August 2018 в 21:32
поделиться

Я искал какое-то время, и, похоже, существуют разные подходы, вот резюме:

  1. reflections библиотека довольно популярна, если u не ум добавляет зависимость. Это будет выглядеть так:
    Reflections reflections = new Reflections("firstdeveloper.examples.reflections");
    Set<Class<? extends Pet>> classes = reflections.getSubTypesOf(Pet.class);
    
  2. 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
    
  3. аннотации на уровне пакета. вот пример:
    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, который всегда будет ограничен уже загруженными классами, если вы не выполняете поиск по каталогам.

25
ответ дан Lakshay Garg 26 August 2018 в 21:32
поделиться
  • 1
    Какой из трех подходов является более эффективным и быстрым? – carlspring 29 May 2016 в 11:34
  • 2
    @carlspring Я не могу сделать абсолютное утверждение об их относительной эффективности, но первая альтернатива (библиотека отражений) работала очень хорошо для меня. – Ahmad Abdelghany 30 May 2016 в 19:45

Попробуйте ClassGraph . (Отказ от ответственности, я автор). ClassGraph поддерживает сканирование для классов, которые реализуют данный интерфейс, либо во время выполнения, либо во время сборки, но и многое другое. ClassGraph может создавать абстрактное представление всего графа классов (все классы, аннотации, методы, параметры метода и поля) в памяти, для всех классов в пути к классам или для классов в белых списках, и вы можете запросить этот графа классов, однако вы хотите. ClassGraph поддерживает больше механизмов спецификации классов и загрузчиков классов , чем любой другой сканер, а также легко работает с новой системой модулей JPMS, поэтому, если вы основываете свой код на ClassGraph, ваш код будет максимально переносимым. См. здесь API.

0
ответ дан Luke Hutchison 26 August 2018 в 21:32
поделиться

Я столкнулся с тем же вопросом. Мое решение состояло в том, чтобы использовать рефлексию для изучения всех методов класса ObjectFactory, исключая те методы, которые не были createXXX (), возвращающие экземпляр одного из моих связанных POJO. Каждый обнаруженный класс добавляется в массив Class [], который затем передается в экземплярный вызов JAXBContext. Это хорошо работает, нужно только загрузить класс ObjectFactory, который все равно понадобился. Мне нужно только поддерживать класс ObjectFactory, задачу, выполняемую вручную (в моем случае, потому что я начал с POJO и использовал схему), или может быть сгенерирован по необходимости xjc. В любом случае, он эффективен, прост и эффективен.

0
ответ дан NDK 26 August 2018 в 21:32
поделиться

Кроме того, если вы пишете плагин IDE (где то, что вы пытаетесь сделать, является относительно общим), тогда IDE обычно предлагает вам более эффективные способы доступа к иерархии классов текущего состояния кода пользователя.

1
ответ дан Uri 26 August 2018 в 21:32
поделиться

Что эриксон сказал лучше всего. Вот связанный вопрос и ответ нить - http://www.velocityreviews.com/forums/t137693-find-all-implementing-classes-in-classpath.html

Библиотека Apache BCEL позволяет вам читать классы без их загрузки. Я считаю, что это будет быстрее, потому что вы сможете пропустить этап проверки. Другая проблема с загрузкой всех классов с помощью загрузчика классов заключается в том, что вы будете испытывать огромное влияние на память, а также непреднамеренно запускать любые статические блоки кода, которые вы, вероятно, не хотите делать.

Ссылка на библиотеку Apache BCEL - http://jakarta.apache.org/bcel/

4
ответ дан user 26 August 2018 в 21:32
поделиться

Да, первым шагом является определение «всех» классов, о которых вы заботитесь. Если у вас уже есть эта информация, вы можете перечислить каждую из них и использовать instanceof для проверки отношения. Связанная статья находится здесь: http://www.javaworld.com/javaworld/javatips/jw-javatip113.html

4
ответ дан Zhichao 26 August 2018 в 21:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: