2013-03-09 5 views
8

Могу ли я сделать это с отражением или что-то в этом роде?Можно ли получить все классы, реализующие интерфейс?

+4

Почему так много downvotes? Это совершенно правильный вопрос! –

+1

Возможный дубликат http://stackoverflow.com/questions/347248, http://stackoverflow.com/questions/435890 – StarPinkER

+0

попробуйте [ЭТО] (http://tinyurl.com/d5ohdr4) –

ответ

9

Нет надежного способа сделать то, что вы хотите, на 100%. Причина в том, что загрузка классов работает на Java.

Классы на Java загружаются «по запросу». В первый раз, когда класс ссылается на код (статически или динамически), JVM будет использовать текущий загрузчик классов и попытаться загрузить его. КлассLoader не имеет метода, который дает все классы, которые могут быть загружены из него, поэтому вы не можете перебирать классы.

Есть некоторые ненадежные обходные пути. Например, если вы знаете, что ваш ClassLoader будет загружать только классы из определенного каталога или конкретного JAR-файла, вы можете использовать классы, связанные с вашей файловой системой, чтобы найти файлы «.class», тогда вы можете загружайте все (что требует времени и будет потреблять много вашего PermGen, что может быть проблемой), помните, что вы не можете легко выгрузить класс! (если только не выполняете магию ClassLoader)), и используйте рефлексию для фильтрации классов, реализующих ваши интерфейс.

Проблема с этим обходным решением заключается в том, что он, скорее всего, перестанет работать, если вы когда-либо измените развертывание. Например, если вы начнете развертывать JAR-файл, то позже вы решите использовать контейнер сервлета, который будет работать с файлами WAR, ваш код может не работать больше.

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

Самый надежный способ, который я когда-либо реализовал, это использовать обработчик аннотации. Вы пишете аннотацию, вы комментируете свой интерфейс, и вы пишете код, который будет выполняться компилятором во время компиляции, который будет собирать классы, реализующие ваш интерфейс, и сохранять их имена в файле ресурсов. Затем вы пишете класс с методом, который читает этот файл и предоставляет объект класса для каждого имени класса, указанного в этом файле ресурсов.

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

+0

Действительно? Моя IDE делает это просто отлично ... –

+0

@BrianRoach, о, действительно? Теперь вы либо попросите свою IDE перечислить ваши классы, затем CTRL + C, CTRL + V где-то в вашем коде (и обновляйте вручную каждый раз, когда вы добавляете новый класс), или тот факт, что ваша IDE знает, что это полностью бесполезно для кода, который вы используете. Или вы попробуете один из не 100% надежных методов (итерации через вашу файловую систему или внутри файла JAR, находящего файлы .class, или используя другой подход, например тот, который я предлагаю). В частности, IDE знает, что он имеет дело с файловой системой, поэтому он может легко перебирать файлы. Надежность 100%. Бесполезно во время выполнения. –

+0

Или вы можете просто нажать ctrl + T и позволить IDE, например eclipse, показать вам иерархию классов. Неясно, хочет ли OP решение во время выполнения/компиляции. –