Determinar si una clase implementa una interfaz en Java

92

Tengo un Classobjeto. Quiero determinar si el tipo que Classrepresenta el objeto implementa una interfaz específica. Me preguntaba cómo se podría lograr esto.

tengo el siguiente código. Básicamente, lo que hace es obtener una matriz de todas las clases en un paquete específico. Luego, quiero pasar por la matriz y agregar los objetos Class que implementan una interfaz a mi mapa. El problema es que isInstance()toma un objeto como parámetro. No puedo crear una instancia de una interfaz. Así que estoy un poco perdido con esto. ¿Algunas ideas?

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);
    }
}
usuario489041
fuente

Respuestas:

215

Deberías usar isAssignableFrom:

if (YourInterface.class.isAssignableFrom(clazz)) {
    ...
}
Flavio
fuente
Esto funciona si el proyecto es el mismo. Pero si copia el código de interfaz 1: 1, crea un nuevo proyecto y jar, luego intenta cargar ese jar como un complemento, la llamada devolverá falso. Comparar por nombre y luego "funciona", como publicó Roddy. Pero no tengo idea de cómo verificar esto en la forma en que Java finalmente verifica la compatibilidad. Por nombre es un enfoque sucio. El tuyo está bien, por supuesto, si el proyecto es el mismo. ................ QUIZÁS lo estoy haciendo mal: creo una instancia de URLClassLoader para el archivo del complemento y la cargo así. Quizás debería probar con un cargador de clases diferente.
Presidente de Dreamspace
4
Tienes problemas para cargar clases. Si carga la misma clase dos veces con diferentes cargadores de clases, las dos Classinstancias no serán compatibles. Podrías ver errores como java.lang.ClassCastException: com.my.CustomClass cannot be cast to com.my.CustomClasso algo similarmente inexplicable.
Flavio
Ya probé varios enfoques y, al final, resultó que el problema principal que tenía era este: si bien la interfaz de mi complemento y el proyecto principal eran idénticos, no estaban en el mismo lugar, por lo que el espacio de nombres / dirección era diferente. Por cierto, ahora estoy usando: myClassLoader = new URLClassLoader(new URL[] { candidateFile.toURI().toURL() }, LoadedPlugin.class.getClassLoader());and classToLoad = Class.forName("com.blablabla.plugin.Main", true, myClassLoader);y instance = (MyIntf) classToLoad.newInstance();funciona como un encanto.
Presidente de Dreamspace
17

puede usar la siguiente función para obtener todas las interfaces implementadas

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

Puede usar class.getInterfaces()y luego verificar para ver si la clase de interfaz está allí.

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 de los guisantes congelados
fuente
Este enfoque funcionará técnicamente, pero el enfoque mucho más simple y limpio es usarlo isAssignableFromcomo menciona Flavio.
jwj
Sí, eso es cierto, aunque su respuesta ha sido votada a favor más de unas pocas veces y pensé que sería útil agregar algo de contexto. Si bien isAssignableFromes probable que sea preferible usarlo , puede haber casos en los que necesite escanear la lista de interfaces que implementa una clase mirando los nombres.
jwj
Esto en realidad no funciona, getInterfaces () solo funciona si la clase implementa la interfaz directamente, si una superclase implementa la interfaz, o una super interfaz la extiende, esa interfaz no será devuelta por getInterfaces (). Necesita recorrer el árbol de todas las superclases e interfaces para obtener todas las interfaces que implementa la clase.
James Roper
Sin embargo, esa no era la pregunta.
Roddy of the Frozen Peas
1

También puede configurar la instancia agregando ".class"

Class[] classes = ClassUtils.getClasses(handlersPackage);
for(Class clazz : classes)
{
    if(Interface.class.isAssignableFrom(clazz))
    {
        retVal.put(clazz.getSimpleName(), clazz);
    }
}
Manu Navarro
fuente
2
Para cualquiera que esté mirando este enfoque, considere la respuesta de Flavio. Tenga en cuenta que el código en este ejemplo hace algunas cosas que pueden no tener sentido inmediato: ClassUtilsno es parte de Java (está en Guava o Spring y otros marcos), el término Interfacecomo se usa arriba está destinado a referirse a una interfaz específica que se está probando ( es decir, no es una palabra clave de Java en este contexto), y el propósito de retValno se explica ni se menciona en ninguna parte.
jwj