Comment procéder et essayer de trouver toutes les sous-classes d'une classe donnée (ou tous les implémenteurs d'une interface donnée) en Java? Pour l'instant, j'ai une méthode pour le faire, mais je la trouve assez inefficace (c'est le moins qu'on puisse dire). La méthode est la suivante:
- Obtenez une liste de tous les noms de classe qui existent sur le chemin de classe
- Chargez chaque classe et testez pour voir s'il s'agit d'une sous-classe ou d'un implémenteur de la classe ou de l'interface souhaitée
Dans Eclipse, il existe une fonctionnalité intéressante appelée la hiérarchie des types qui parvient à le montrer assez efficacement. Comment procéder et le faire par programme?
Réponses:
Il n'y a pas d'autre moyen de le faire que ce que vous avez décrit. Pensez-y - comment peut-on savoir quelles classes étendent ClassX sans analyser chaque classe sur le chemin de classe?
Eclipse ne peut vous parler que des super et des sous-classes dans ce qui semble être un temps "efficace" car il a déjà toutes les données de type chargées au point où vous appuyez sur le bouton "Afficher dans la hiérarchie des types" (car il s'agit de compilant constamment vos classes, sait tout sur le chemin de classe, etc.).
la source
reflections.getSubTypesOf(aClazz))
lienLa recherche de classes n'est pas facile avec Java pur.
Le framework Spring propose une classe appelée ClassPathScanningCandidateComponentProvider qui peut faire ce dont vous avez besoin. L'exemple suivant trouverait toutes les sous-classes de MyClass dans le package org.example.package
Cette méthode a l'avantage supplémentaire d'utiliser un analyseur de bytecode pour trouver les candidats, ce qui signifie qu'elle ne chargera pas toutes les classes qu'elle analyse.
la source
Il n'est pas possible de le faire en utilisant uniquement l'API Java Reflections intégrée.
Il existe un projet qui effectue l'analyse et l'indexation nécessaires de votre chemin de classe afin que vous puissiez accéder à ces informations ...
Réflexions
(Avertissement: je ne l'ai pas utilisé, mais la description du projet semble correspondre exactement à vos besoins.)
la source
N'oubliez pas que la Javadoc générée pour une classe inclura une liste de sous-classes connues (et pour les interfaces, les classes d'implémentation connues).
la source
Essayez ClassGraph . (Avertissement, je suis l'auteur). ClassGraph prend en charge l'analyse des sous-classes d'une classe donnée, soit au moment de l'exécution, soit au moment de la construction, mais aussi beaucoup plus. ClassGraph peut créer une représentation abstraite du graphique de classe entier (toutes les classes, annotations, méthodes, paramètres de méthode et champs) en mémoire, pour toutes les classes sur le chemin de classe, ou pour les classes dans des packages en liste blanche, et vous pouvez cependant interroger ce graphique de classe tu veux. ClassGraph soutient plusieurs mécanismes de spécification classpath et classloaders que tout autre scanner, et fonctionne également de façon transparente avec le nouveau système de module JPMS, donc si vous basez votre code sur ClassGraph, votre code sera au maximum portable. Voir l'API ici.
la source
Je l'ai fait il y a plusieurs années. La façon la plus fiable de le faire (c'est-à-dire avec les API Java officielles et sans dépendances externes) est d'écrire un doclet personnalisé pour produire une liste qui peut être lue au moment de l'exécution.
Vous pouvez l'exécuter à partir de la ligne de commande comme ceci:
ou exécutez-le à partir de fourmi comme ceci:
Voici le code de base:
Pour simplifier, j'ai supprimé l'analyse des arguments de la ligne de commande et j'écris dans System.out plutôt que dans un fichier.
la source
Je sais que j'ai quelques années de retard à cette fête, mais je suis tombé sur cette question en essayant de résoudre le même problème. Vous pouvez utiliser la recherche interne d'Eclipse par programmation, si vous écrivez un plugin Eclipse (et ainsi profiter de leur mise en cache, etc.), pour trouver des classes qui implémentent une interface. Voici ma première coupe (très grossière):
Le premier problème que je vois jusqu'à présent est que je n'attrape que les classes qui implémentent directement l'interface, pas toutes leurs sous-classes - mais une petite récursivité n'a jamais blessé personne.
la source
En gardant à l'esprit les limitations mentionnées dans les autres réponses, vous pouvez également utiliser openpojo's
PojoClassFactory
( disponible sur Maven ) de la manière suivante:Où
packageRoot
est la chaîne racine des packages dans lesquels vous souhaitez rechercher (par exemple"com.mycompany"
ou même juste"com"
), etSuperclass
est votre supertype (cela fonctionne également sur les interfaces).la source
Je viens d'écrire une démo simple pour utiliser le
org.reflections.Reflections
pour obtenir des sous-classes de classe abstraite:https://github.com/xmeng1/ReflectionsDemo
la source
En fonction de vos besoins particuliers, dans certains cas, le mécanisme du chargeur de services Java peut atteindre ce que vous recherchez.
En bref, il permet aux développeurs de déclarer explicitement qu'une classe sous-classe une autre classe (ou implémente une interface) en la répertoriant dans un fichier dans le répertoire du fichier JAR / WAR
META-INF/services
. Il peut ensuite être découvert à l'aide de lajava.util.ServiceLoader
classe qui, lorsqu'elle reçoit unClass
objet, générera des instances de toutes les sous-classes déclarées de cette classe (ou, siClass
représente une interface, toutes les classes implémentant cette interface).Le principal avantage de cette approche est qu'il n'est pas nécessaire d'analyser manuellement le chemin de classe entier pour les sous-classes - toute la logique de découverte est contenue dans la
ServiceLoader
classe, et elle ne charge que les classes explicitement déclarées dans leMETA-INF/services
répertoire (pas toutes les classes sur le chemin de classe) .Il existe cependant certains inconvénients:
META-INF/services
répertoire. Ceci représente une charge supplémentaire pour le développeur et peut être sujet à erreurs.ServiceLoader.iterator()
génère des instances de sous-classe, pas leursClass
objets. Cela provoque deux problèmes:Apparemment, Java 9 corrigera certaines de ces lacunes (en particulier celles concernant l'instanciation des sous-classes).
Un exemple
Supposons que vous souhaitiez trouver des classes qui implémentent une interface
com.example.Example
:La classe
com.example.ExampleImpl
implémente cette interface:Vous déclareriez que la classe
ExampleImpl
est une implémentation deExample
en créant un fichierMETA-INF/services/com.example.Example
contenant le textecom.example.ExampleImpl
.Ensuite, vous pouvez obtenir une instance de chaque implémentation de
Example
(y compris une instance deExampleImpl
) comme suit:la source
Il convient également de noter que cela ne trouvera bien sûr que toutes les sous-classes qui existent sur votre chemin de classe actuel. Vraisemblablement, cela convient à ce que vous regardez actuellement, et il est probable que vous ayez envisagé cela, mais si vous avez à un moment donné libéré une non-
final
classe dans la nature (pour différents niveaux de "sauvage"), il est tout à fait possible que quelqu'un d'autre a écrit sa propre sous-classe que vous ne connaissez pas.Ainsi, si vous vouliez voir toutes les sous-classes parce que vous voulez apporter un changement et que vous allez voir comment cela affecte le comportement des sous-classes - alors gardez à l'esprit les sous-classes que vous ne pouvez pas voir. Idéalement, toutes vos méthodes non privées, et la classe elle-même doit être bien documentée; apportez des modifications conformément à cette documentation sans modifier la sémantique des méthodes / champs non privés et vos modifications doivent être rétrocompatibles, pour toute sous-classe qui a suivi votre définition de la superclasse au moins.
la source
La raison pour laquelle vous voyez une différence entre votre implémentation et Eclipse est que vous effectuez une analyse à chaque fois, tandis qu'Eclipse (et d'autres outils) analysent une seule fois (lors du chargement du projet la plupart du temps) et créent un index. La prochaine fois que vous demanderez les données, elles ne seront plus analysées, mais regardez l'index.
la source
J'utilise une bibliothèque de réflexion, qui analyse votre chemin de classe pour toutes les sous-classes: https://github.com/ronmamo/reflections
Voici comment cela se ferait:
la source
Ajoutez-les à une carte statique à l'intérieur (this.getClass (). GetName ()) du constructeur des classes parent (ou créez-en un par défaut) mais cela sera mis à jour lors de l'exécution. Si l'initialisation paresseuse est une option, vous pouvez essayer cette approche.
la source
Vous pouvez utiliser la bibliothèque org.reflections puis créer un objet de la classe Reflections. En utilisant cet objet, vous pouvez obtenir la liste de toutes les sous-classes d'une classe donnée. https://www.javadoc.io/doc/org.reflections/reflections/0.9.10/org/reflections/Reflections.html
la source
J'avais besoin de le faire comme cas de test, pour voir si de nouvelles classes avaient été ajoutées au code. C'est ce que j'ai fait
la source