Как можно найти и попытаться найти все подклассы данного класса (или всех разработчиков данного интерфейса) в Java? На данный момент у меня есть способ сделать это, но я нахожу его довольно неэффективным (если не сказать больше). Метод таков:
- Получить список всех имен классов, которые существуют на пути к классам
- Загрузите каждый класс и проверьте, является ли он подклассом или разработчиком нужного класса или интерфейса.
В Eclipse есть замечательная функция, которая называется Type Hierarchy, которая позволяет показать это довольно эффективно. Как можно это сделать и сделать это программно?
Ответы:
Нет другого способа сделать это, кроме того, что вы описали. Подумайте об этом - как кто-нибудь может знать, какие классы расширяют ClassX, не сканируя каждый класс на пути к классам?
Eclipse может рассказать вам о супер и подклассах только в то время, которое кажется «эффективным», поскольку в него уже загружены все данные о типах в тот момент, когда вы нажимаете кнопку «Показать в иерархии типов» (поскольку постоянно собирать ваши классы, знает обо всем на пути к классам и т. д.).
источник
reflections.getSubTypesOf(aClazz))
ссылкеСканирование для классов не просто с чистой Java.
Платформа Spring предлагает класс ClassPathScanningCandidateComponentProvider, который может делать то, что вам нужно. В следующем примере все подклассы MyClass будут найдены в пакете org.example.package
Этот метод имеет дополнительное преимущество использования анализатора байт-кода для поиска кандидатов, что означает, что он не будет загружать все сканируемые классы.
источник
Это невозможно сделать, используя только встроенный Java Reflections API.
Существует проект, который выполняет необходимое сканирование и индексацию вашего classpath, чтобы вы могли получить доступ к этой информации ...
Размышления
(Отказ от ответственности: я не использовал его, но описание проекта, кажется, точно соответствует вашим потребностям.)
источник
Не забывайте, что сгенерированный Javadoc для класса будет включать список известных подклассов (и для интерфейсов, известных реализующих классов).
источник
Попробуйте ClassGraph . (Отказ от ответственности, я автор). ClassGraph поддерживает сканирование для подклассов данного класса, во время выполнения или во время сборки, но также и многое другое. ClassGraph может построить абстрактное представление всего графа классов (все классы, аннотации, методы, параметры методов и поля) в памяти, для всех классов в пути к классам или для классов в пакетах из белого списка, и вы можете запросить этот класс классов, однако вы хотите. ClassGraph поддерживает больше механизмов спецификации classpath и загрузчиков классов, чем любой другой сканер, а также без проблем работает с новой модульной системой JPMS, поэтому, если вы основываете свой код на ClassGraph, ваш код будет максимально переносимым. Смотрите API здесь.
источник
Я сделал это несколько лет назад. Самый надежный способ сделать это (т. Е. С помощью официальных API-интерфейсов Java и без внешних зависимостей) - это написать собственный доклет для создания списка, который можно прочитать во время выполнения.
Вы можете запустить его из командной строки следующим образом:
или запустите его из муравья так:
Вот основной код:
Для простоты я удалил разбор аргументов командной строки и пишу в System.out, а не в файл.
источник
Я знаю, что опоздал на эту вечеринку на несколько лет, но я наткнулся на этот вопрос, пытаясь решить ту же проблему. Вы можете использовать внутренний поиск Eclipse программно, если вы пишете плагин Eclipse (и, следовательно, используете их кэширование и т. Д.), Чтобы найти классы, которые реализуют интерфейс. Вот мой (очень грубый) первый разрез:
Первая проблема, которую я вижу до сих пор, заключается в том, что я ловлю только те классы, которые непосредственно реализуют интерфейс, а не все их подклассы - но небольшая рекурсия никогда никому не повредит.
источник
Принимая во внимание ограничения, упомянутые в других ответах, вы также можете использовать openpojo
PojoClassFactory
( доступно на Maven ) следующим образом:Где
packageRoot
находится корневая строка пакетов, в которых вы хотите искать (например,"com.mycompany"
или просто"com"
), иSuperclass
ваш супертип (это работает и на интерфейсах).источник
Я просто пишу простую демонстрацию, чтобы использовать
org.reflections.Reflections
подклассы абстрактного класса:https://github.com/xmeng1/ReflectionsDemo
источник
В зависимости от ваших конкретных требований, в некоторых случаях механизм загрузчика сервисов Java может достичь того, что вам нужно.
Короче говоря, это позволяет разработчикам явно объявить, что класс подклассирует некоторый другой класс (или реализует некоторый интерфейс), перечислив его в файл в каталоге файла JAR / WAR
META-INF/services
. Затем его можно обнаружить с помощьюjava.util.ServiceLoader
класса, который приClass
объекта, будет генерировать экземпляры всех объявленных подклассов этого класса (или, еслиClass
представляет интерфейс, все классы, реализующие этот интерфейс).Основное преимущество этого подхода состоит в том, что нет необходимости вручную сканировать весь путь к классам для поиска подклассов - вся логика обнаружения содержится внутри
ServiceLoader
класса, и он загружает только классы, явно объявленные вMETA-INF/services
каталоге (не каждый класс в пути к классам) ,Есть, однако, некоторые недостатки:
META-INF/services
каталоге. Это дополнительная нагрузка на разработчика и может быть подвержена ошибкам.ServiceLoader.iterator()
Создает экземпляры подкласса, а не ихClass
объекты. Это вызывает две проблемы:Очевидно, в Java 9 будут устранены некоторые из этих недостатков (в частности, те, которые касаются создания экземпляров подклассов).
Пример
Предположим, вы заинтересованы в поиске классов, которые реализуют интерфейс
com.example.Example
:Класс
com.example.ExampleImpl
реализует этот интерфейс:Вы бы объявили, что класс
ExampleImpl
является реализациейExample
, создав файл,META-INF/services/com.example.Example
содержащий текстcom.example.ExampleImpl
.Затем вы можете получить экземпляр каждой реализации
Example
(включая экземплярExampleImpl
) следующим образом:источник
Следует также отметить, что это, конечно, только найдет все те подклассы, которые существуют на вашем текущем пути к классам. Предположительно, это нормально для того, на что вы сейчас смотрите, и есть вероятность, что вы действительно обдумали это, но если вы когда-либо выпустили
final
класс в дикую природу (для разных уровней «дикого»), то вполне возможно, что кто-то другой написал свой собственный подкласс, о котором вы не будете знать.Таким образом, если вам захотелось увидеть все подклассы, потому что вы хотите внести изменения и увидите, как это влияет на поведение подклассов, - имейте в виду подклассы, которые вы не видите. В идеале все ваши не частные методы и сам класс должны быть хорошо документированы; вносите изменения в соответствии с этой документацией, не изменяя семантику методов / непубличных полей, и ваши изменения должны быть обратно-совместимыми, по крайней мере, для любого подкласса, который следует вашему определению суперкласса.
источник
Причина, по которой вы видите разницу между вашей реализацией и Eclipse, заключается в том, что вы сканируете каждый раз, тогда как Eclipse (и другие инструменты) сканируют только один раз (во время загрузки проекта большую часть времени) и создают индекс. В следующий раз, когда вы запрашиваете данные, они не сканируются снова, но посмотрите на индекс.
источник
Я использую библиотеку отражений, которая сканирует ваш путь к классам для всех подклассов: https://github.com/ronmamo/reflections
Вот как это будет сделано:
источник
Добавьте их к статической карте внутри (this.getClass (). GetName ()) конструктора родительских классов (или создайте класс по умолчанию), но он будет обновляться во время выполнения. Если ленивая инициализация является опцией, вы можете попробовать этот подход.
источник
Вы можете использовать библиотеку org.reflections, а затем создать объект класса Reflections. Используя этот объект, вы можете получить список всех подклассов данного класса. https://www.javadoc.io/doc/org.reflections/reflections/0.9.10/org/reflections/Reflections.html
источник
Мне нужно было сделать это в качестве контрольного примера, чтобы увидеть, были ли добавлены новые классы в код. Это то что я сделал
источник