Déterminer si une classe implémente une interface en Java

92

J'ai un Classobjet. Je veux déterminer si le type que l' Classobjet représente implémente une interface spécifique. Je me demandais comment cela pouvait être réalisé?

J'ai le code suivant. Fondamentalement, il obtient un tableau de toutes les classes dans un package spécifié. Je veux ensuite parcourir le tableau et ajouter les objets Class qui implémentent une interface à ma carte. Le problème est qu'il isInstance()prend un objet comme paramètre. Je ne peux pas instancier une interface. Donc je suis un peu perdu avec ça. Des idées?

Class[] classes = ClassUtils.getClasses(handlersPackage);
for(Class clazz : classes)
{
    if(clazz.isInstance(/*Some object*/)) //Need something in this if statement
    {
        retVal.put(clazz.getSimpleName(), clazz);
    }
}
user489041
la source

Réponses:

215

Vous devez utiliser isAssignableFrom:

if (YourInterface.class.isAssignableFrom(clazz)) {
    ...
}
Flavio
la source
Cela fonctionne si le projet est le même. Mais si vous copiez le code d'interface 1: 1, créez un nouveau projet et un nouveau fichier jar, puis essayez de charger ce fichier en tant que plugin, l'appel retournera false. En comparant par nom, alors «fonctionne», comme l'a posté Roddy. Mais je ne sais pas comment vérifier cela de la manière dont Java vérifie finalement la compatibilité. Par son nom, c'est une approche sale. Le vôtre va bien, bien sûr, si le projet est le même. ................ PEUT-ÊTRE Je fais mal: je crée une instance d'URLClassLoader pour le fichier du plugin et la charge comme ça. Je devrais peut-être essayer un autre chargeur de classe.
Dreamspace President
4
Vous rencontrez des problèmes de chargement de classe. Si vous chargez la même classe deux fois avec des chargeurs de classe différents, les deux Classinstances ne seront pas compatibles. Vous pourriez voir des erreurs comme java.lang.ClassCastException: com.my.CustomClass cannot be cast to com.my.CustomClassou quelque chose de similaire inexplicable.
Flavio
J'ai maintenant essayé différentes approches, et à la fin, il s'est avéré que le principal problème que j'avais était le suivant: alors que l'interface de mon plugin et de mon projet principal étaient identiques, ils n'étaient pas au même endroit, donc l'espace de noms / l'adresse était différent. Btw., J'utilise maintenant: myClassLoader = new URLClassLoader(new URL[] { candidateFile.toURI().toURL() }, LoadedPlugin.class.getClassLoader());et classToLoad = Class.forName("com.blablabla.plugin.Main", true, myClassLoader);et instance = (MyIntf) classToLoad.newInstance();fonctionne comme un charme.
Dreamspace President
17

vous pouvez utiliser la fonction ci-dessous pour obtenir toutes les interfaces implémentées

Class[] intfs = clazz.getInterfaces();
Ankur
la source
10

Vous pouvez utiliser class.getInterfaces(), puis vérifier si la classe d'interface s'y trouve.

Class someInterface; // the interface you want to check for 
Class x; // 
Class[] interfaces = x.getInterfaces();

for (Class i : interfaces) {
    if (i.toString().equals(someInterface.toString()) {
        // if this is true, the class implements the interface you're looking for
    }
}
Roddy des pois surgelés
la source
Cette approche fonctionnera techniquement, mais l'approche beaucoup plus simple et plus propre consiste à l'utiliser isAssignableFromcomme le mentionne Flavio.
jwj
Oui, c'est vrai, bien que votre réponse ait été votée plusieurs fois et j'ai pensé qu'il serait utile d'ajouter un peu de contexte. Bien que l'utilisation isAssignableFromsoit probablement préférable, il peut y avoir des cas où vous devez parcourir la liste des interfaces qu'une classe implémente en regardant les noms.
jwj
Cela ne fonctionne pas, getInterfaces () ne fonctionne que si la classe implémente l'interface directement, si une superclasse implémente l'interface, ou si une super interface l'étend, cette interface ne sera pas retournée par getInterfaces (). Vous devez parcourir l'arborescence de toutes les super classes et interfaces afin d'obtenir toutes les interfaces implémentées par la classe.
James Roper
Ce n'était pas la question cependant.
Roddy of the Frozen Peas
1

Vous pouvez également définir l'instance en ajoutant ".class"

Class[] classes = ClassUtils.getClasses(handlersPackage);
for(Class clazz : classes)
{
    if(Interface.class.isAssignableFrom(clazz))
    {
        retVal.put(clazz.getSimpleName(), clazz);
    }
}
Manu Navarro
la source
2
Pour tous ceux qui envisagent cette approche, veuillez considérer la réponse de Flavio. Notez que le code de cet exemple fait certaines choses qui peuvent ne pas avoir de sens immédiat: ClassUtilsne fait pas partie de Java (il est dans Guava ou Spring et d'autres frameworks), le terme Interfaceutilisé ci-dessus est destiné à faire référence à une interface spécifique en cours de test ( c'est-à-dire, ce n'est pas un mot-clé Java dans ce contexte), et le but de retValn'est expliqué ni mentionné nulle part.
jwj