Determine se uma classe implementa uma interface em Java

89

Eu tenho um Classobjeto. Quero determinar se o tipo que o Classobjeto representa implementa uma interface específica. Eu queria saber como isso poderia ser alcançado?

Eu tenho o seguinte código. Basicamente, o que ele faz é obter um array de todas as classes em um pacote especificado. Em seguida, desejo percorrer a matriz e adicionar os objetos Class que implementam uma interface ao meu mapa. O problema é que isInstance()usa um objeto como parâmetro. Não consigo instanciar uma interface. Então, estou meio perdida com isso. Alguma ideia?

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
fonte

Respostas:

212

Você deve usar isAssignableFrom:

if (YourInterface.class.isAssignableFrom(clazz)) {
    ...
}
Flavio
fonte
Isso funciona se o projeto for o mesmo. Mas se você copiar o código de interface 1: 1, criar um novo projeto e jar e, em seguida, tentar carregar esse jar como um plugin, a chamada retornará false. Comparar pelo nome e depois por "funciona", como postou Roddy. Mas não tenho ideia de como verificar isso da maneira como o Java eventualmente verifica a compatibilidade. Pelo nome é uma abordagem suja. O seu está ótimo, claro, se o projeto for o mesmo. ................ TALVEZ estou fazendo errado: crio uma instância URLClassLoader para o arquivo de plug-in e carrego-o assim. Talvez eu deva tentar um carregador de classes diferente.
Dreamspace Presidente
4
Você está tendo problemas com o carregamento da turma. Se você carregar a mesma classe duas vezes com carregadores de classe diferentes, as duas Classinstâncias não serão compatíveis. Você pode ver erros como java.lang.ClassCastException: com.my.CustomClass cannot be cast to com.my.CustomClassou algo igualmente inexplicável.
Flavio
Eu já tentei várias abordagens e, no final, descobri que o principal problema que eu tinha era este: embora a interface em meu plugin e projeto principal fossem idênticos, eles não estavam no mesmo lugar, então o namespace / endereço era diferente. A propósito, agora estou usando: myClassLoader = new URLClassLoader(new URL[] { candidateFile.toURI().toURL() }, LoadedPlugin.class.getClassLoader());e classToLoad = Class.forName("com.blablabla.plugin.Main", true, myClassLoader);e instance = (MyIntf) classToLoad.newInstance();Funciona como um encanto.
Dreamspace Presidente
17

você pode usar a função abaixo para obter todas as interfaces implementadas

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

Você pode usar class.getInterfaces()e, em seguida, verificar se a classe de interface está lá.

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 das Ervilhas Congeladas
fonte
Esta abordagem irá funcionar tecnicamente, mas a abordagem muito mais simples e limpa é usar isAssignableFromcomo Flavio menciona.
jwj de
Sim, é verdade, embora sua resposta tenha sido votada mais do que algumas vezes e eu achei que seria útil adicionar algum contexto. Embora o uso isAssignableFromseja provavelmente preferível, pode haver casos em que você precise examinar a lista de interfaces que uma classe implementa olhando os nomes.
jwj de
Isso realmente não funciona, getInterfaces () só funciona se a classe implementa a interface diretamente, se uma superclasse implementa a interface ou uma superinterface a estende, essa interface não será retornada por getInterfaces (). Você precisa percorrer a árvore de todas as superclasses e interfaces para obter todas as interfaces que a classe implementa.
James Roper
Essa não era a questão, no entanto.
Roddy of the Frozen Peas
1

Você também pode definir a instância adicionando ".class"

Class[] classes = ClassUtils.getClasses(handlersPackage);
for(Class clazz : classes)
{
    if(Interface.class.isAssignableFrom(clazz))
    {
        retVal.put(clazz.getSimpleName(), clazz);
    }
}
Manu Navarro
fonte
2
Para quem está olhando para essa abordagem, considere a resposta de Flavio. Observe que o código neste exemplo faz algumas coisas que podem não fazer sentido imediatamente: ClassUtilsnão faz parte do Java (está no Guava ou Spring e outras estruturas), o termo Interfaceusado acima se destina a referir-se a uma interface específica sendo testada ( ou seja, não é uma palavra-chave Java neste contexto), e o propósito de retValnão é explicado ou mencionado em qualquer lugar.
jwj de