160 votes

Lors de l’exécution, trouver toutes les classes dans une application Java qui s’étendent à une classe de base

Je veux faire quelque chose comme ceci:

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

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

Donc, je tiens à regarder toutes les classes dans mon application de l'univers, et quand j'en trouve un qui descend de l'Animal, je veux créer un nouvel objet de ce type et l'ajouter à la liste. Cela me permet d'ajouter des fonctionnalités sans avoir à mettre à jour une liste de choses. Je ne peux éviter le suivant:

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

Avec l'approche ci-dessus, je peux tout simplement créer une nouvelle classe qui étend la classe des Animaux, et il va aller chercher automatiquement.

Mise à JOUR: 10/16/2008 9:00 h, Heure normale du Pacifique:

Cette question a généré beaucoup de réponses, merci à vous. À partir des réponses et mes recherches, j'ai trouvé que ce que je veux vraiment faire, c'est juste pas possible en Java. Il existe des approches, telles que ddimitrov de ServiceLoader mécanisme de travail-mais ils sont très lourd pour ce que je veux, et je crois que j'ai tout simplement déplacer le problème à partir du code Java à un fichier de configuration externe.

Une autre manière de formuler ce que je veux: une fonction statique à mon Animal de la classe de découvertes et de instancie toutes les classes qui héritent de l'Animal, sans autre configuration de codage. Si je dois configurer, je pourrais tout aussi bien les instancier dans l'Animal de la classe de toute façon. Je comprends que le fait qu'un programme Java est juste une fédération lâche .les fichiers de classe que c'est juste la façon dont il est.

Fait intéressant, il semble que ce soit assez banale en C#.

171voto

IvanNik Points 411

J’utilise org.reflections

http://code.google.com/p/Reflections/

36voto

ddimitrov Points 2005

La Java de manière à faire ce que vous voulez est d'utiliser le ServiceLoader mécanisme.

Aussi beaucoup de gens rouler leur propre en ayant un fichier dans une bien connue chemin de classe (càd /META-INF/services/myplugin.les propriétés), puis à l'aide du chargeur de classe.getResources() pour énumérer tous les fichiers portant ce nom de tous les pots. Cela permet à chaque bocal pour l'exportation de leurs propres fournisseurs et vous pouvez instancier par la réflexion à l'aide de la Classe.forName()

10voto

Paul Sonier Points 25528

Penser à ce à partir d'un aspect-oriented point de vue; ce que vous voulez faire, vraiment, est de savoir toutes les classes au moment de l'exécution, ce qui a permis à l'Animal de la classe. (Je pense que c'est un peu plus description exacte de votre problème que votre titre; sinon, je ne pense pas que vous avez un runtime question.)

Donc, ce que je pense que vous voulez est de créer un constructeur de votre classe de base (Animal), ce qui ajoute à votre tableau statique (je préfère ArrayLists, moi-même, mais à chacun son) le type de la Classe actuelle qui est instanciée.

Donc, à peu près;

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

Bien sûr, vous aurez besoin d'un constructeur statique sur l'Animal pour initialiser instantiatedDerivedClass... je pense que c'vais faire ce que vous voulez probablement. Notez que c'est l'exécution de chemin à charge; si vous avez un Chien classe qui dérive de l'Animal, qui n'est jamais invoquée, vous n'aurez pas dans votre Animal de la Classe liste.

8voto

jonathan-stafford Points 2785

Malheureusement ce n’est pas tout à fait possible que le chargeur de classe ne vous dirai pas quelles classes sont disponibles. Vous pouvez, toutefois, obtenir assez proches, quelque chose comme ceci :

Edit : johnstok est correct (dans les commentaires) que cela ne fonctionne que pour les applications Java autonomes et ne fonctionnera pas sous un serveur d’applications.

1voto

JohnnyLambada Points 4554

Merci tous ceux qui ont répondu à cette question.

Il semble que ce est en effet une noix dure à casser. J'ai fini par abandonner et de la création d'un tableau statique et de lecture dans mon baseclass.

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;
    }
}

Il semble que Java n'est tout simplement pas mis en place pour l'auto-identification de la façon dont C# est. Je suppose que le problème est que depuis une application Java est juste une collection de .les fichiers de classe dans un répertoire / fichier jar quelque part, le moteur d'exécution ne sais pas à propos d'une classe jusqu'à ce qu'il est référencé. À cette époque, le chargeur de charges-ce que je suis en train de faire est de le découvrir avant que je référence qui n'est pas possible sans sortir du système de fichiers et à la recherche.

J'aime toujours code que vous pouvez découvrir lui-même au lieu d'avoir à me dire à propos de lui-même, mais, hélas, cela fonctionne aussi.

Merci encore!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X