Во время выполнения найдите все классы в приложении Java, которые расширяют базовый класс

139
задан JohnnyLambada 10 May 2019 в 14:53
поделиться

7 ответов

Java способ сделать, что Вы хотите, должен использовать механизм ServiceLoader .

Также многие люди прокручивают свое собственное при наличии файла в известном месте пути к классу (т.е./META-INF/services/myplugin.properties) и затем использование ClassLoader.getResources () для перечисления всех файлов с этим именем от всех банок. Это позволяет каждой банке экспортировать своих собственных поставщиков, и можно инстанцировать их отражением с помощью Class.forName ()

34
ответ дан 2 revs, 2 users 94% 10 May 2019 в 14:53
поделиться

Думайте об этом с аспектно-ориентированной точки зрения; то, что Вы хотите сделать, действительно, знают все классы во времени выполнения, которые расширили класс Животных. (Я думаю, что это - немного более детальное описание Вашей проблемы, чем Ваш заголовок; иначе я не думаю, что у Вас есть вопрос во время выполнения.)

Поэтому то, что я думаю, что Вы хотите, должно создать конструктора Вашего базового класса (Животное), которое добавляет к Вашему статическому массиву (я предпочитаю ArrayLists, сам, но каждому их собственное) тип текущего Класса, который инстанцируют.

Так, примерно;

public abstract class Animal
    {
    private static ArrayList<Class> instantiatedDerivedTypes;
    public Animal() {
        Class derivedClass = this.getClass();
        if (!instantiatedDerivedClass.contains(derivedClass)) {
            instantiatedDerivedClass.Add(derivedClass);
        }
    }

, Конечно, Вам будет нужен статический конструктор на Животном для инициализации instantiatedDerivedClass... Я думаю, что это сделает то, что Вы, вероятно, хотите. Обратите внимание, что это зависимо от предшествующего пути развития выполнением; если у Вас будет класс Собаки, который происходит из Животного, которое никогда не вызывается, то у Вас не будет его в Вашем Списке учащихся Животных.

9
ответ дан Paul Sonier 10 May 2019 в 14:53
поделиться

К сожалению, это не совершенно возможно, поскольку ClassLoder не скажет Вам, какие классы доступны. Можно, однако, получить довольно близкое выполнение чего-то вроде этого:

for (String classpathEntry : System.getProperty("java.class.path").split(System.getProperty("path.separator"))) {
    if (classpathEntry.endsWith(".jar")) {
        File jar = new File(classpathEntry);

        JarInputStream is = new JarInputStream(new FileInputStream(jar));

        JarEntry entry;
        while( (entry = is.getNextJarEntry()) != null) {
            if(entry.getName().endsWith(".class")) {
                // Class.forName(entry.getName()) and check
                //   for implementation of the interface
            }
        }
    }
}

Редактирование: johnstok корректен (в комментариях), что это только работает на автономные JAVA-приложения и не будет работать под сервером приложений.

6
ответ дан Renaud 10 May 2019 в 14:53
поделиться

Java динамично загружает классы, таким образом, Ваша вселенная классов была бы только теми, которые были уже загружены (и еще не разгружены). Возможно, можно сделать что-то с пользовательским загрузчиком класса, который мог проверить супертипы каждого загруженного класса. Я не думаю, что существует API для запросов набора загруженных классов.

2
ответ дан thoroughly 10 May 2019 в 14:53
поделиться

Спасибо все, кто ответил на этот вопрос.

кажется, что это - действительно трудная задача. Я закончил тем, что сдался и создал статический массив и метод считывания в моем базовом классе.

public abstract class Animal{
    private static Animal[] animals= null;
    public static Animal[] getAnimals(){
        if (animals==null){
            animals = new Animal[]{
                new Dog(),
                new Cat(),
                new Lion()
            };
        }
        return animals;
    }
}

кажется, что Java просто не настраивается для self-discoverability путем, C#. Я предполагаю, что проблема состоит в том, что, так как приложение Java является просто набором .class, выходит друг за другом в каталоге / файл банки где-нибудь, время выполнения не знает о классе, пока на это не ссылаются. В то время загрузчик загружает его - что я пытаюсь сделать, обнаруживают его, прежде чем я сошлюсь на него, который не возможен, не выходя в файловую систему и взгляд.

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

Еще раз спасибо!

1
ответ дан JohnnyLambada 10 May 2019 в 14:53
поделиться

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

0
ответ дан pdeva 10 May 2019 в 14:53
поделиться

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

public class Dog extends Animal{

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

Это требует, чтобы Вы добавили этот код ко всем включенным классам. Но это старается не иметь большой ужасный цикл где-нибудь, тестируя каждый класс, ищущий детей Животного.

0
ответ дан 10 May 2019 в 14:53
поделиться
Другие вопросы по тегам:

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