Во время выполнения найдите все классы в приложении Java, которые расширяют базовый класс - PullRequest
137 голосов
/ 15 октября 2008

Я хочу сделать что-то вроде этого:

List<Animal> animals = new ArrayList<Animal>();

for( Class c: list_of_all_classes_available_to_my_app() )
   if (c is Animal)
      animals.add( new c() );

Итак, я хочу посмотреть на все классы во вселенной моего приложения, и когда я найду тот, который происходит от Animal, я хочу создать новый объект этого типа и добавить его в список. Это позволяет мне добавлять функциональность без обновления списка вещей. Я могу избежать следующего:

List<Animal> animals = new ArrayList<Animal>();
animals.add( new Dog() );
animals.add( new Cat() );
animals.add( new Donkey() );
...

Используя описанный выше подход, я могу просто создать новый класс, расширяющий Animal, и он будет автоматически выбран.

ОБНОВЛЕНИЕ: 16.10.2008 9:00 по тихоокеанскому стандартному времени:

Этот вопрос вызвал много хороших ответов - спасибо. Из ответов и моих исследований я обнаружил, что то, что я действительно хочу сделать, просто невозможно в Java. Существуют подходы, такие как механизм ServiceLoader ddimitrov, который может работать, но они очень тяжелы для того, что я хочу, и я считаю, что я просто перенесу проблему из кода Java во внешний файл конфигурации. Обновление 5 / 10/19 (11 лет спустя!) В настоящее время есть несколько библиотек, которые могут помочь с этим, согласно @ 1015 * answer org.reflections @ IvanNik *. Также ClassGraph от ответа @Luke Hutchison выглядит интересно. В ответах есть еще несколько возможностей.

Еще один способ заявить, что я хочу: статическая функция в моем классе Animal находит и создает все классы, которые наследуются от Animal, без какой-либо дальнейшей настройки / кодирования. Если мне нужно настроить, я все равно могу просто создать их экземпляр в классе Animal. Я понимаю это, потому что программа на Java - это просто свободная федерация файлов .class, и это именно так.

Интересно, кажется, что это довольно тривиально в C #.

Ответы [ 13 ]

0 голосов
/ 29 апреля 2011

Я решил эту проблему довольно элегантно, используя аннотации на уровне пакета, а затем сделал эту аннотацию в качестве аргумента списком классов.

Поиск классов Java, реализующих интерфейс

Реализации просто нужно создать package-info.java и добавить волшебную аннотацию со списком классов, которые они хотят поддерживать.

0 голосов
/ 15 октября 2008

Один из способов - заставить классы использовать статические инициализаторы ... Я не думаю, что они наследуются (это не сработает, если они есть):

public class Dog extends Animal{

static
{
   Animal a = new Dog();
   //add a to the List
}

Требуется, чтобы вы добавили этот код ко всем участвующим классам. Но это позволяет избежать большого уродливого цикла, где каждый класс ищет детей Animal.

0 голосов
/ 15 октября 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...