Teste se o objeto implementa interface

149

Provavelmente isso já foi feito antes, mas uma pesquisa rápida trouxe apenas a mesma pergunta para C #. Veja aqui.

O que basicamente quero fazer é verificar se um determinado objeto implementa uma determinada interface.

Eu meio que descobri uma solução, mas isso não é confortável o suficiente para usá-la frequentemente em declarações if ou case e eu estava imaginando se o Java não tem solução embutida.

public static Boolean implementsInterface(Object object, Class interf){
    for (Class c : object.getClass().getInterfaces()) {
        if (c.equals(interf)) {
            return true;
        }
    }
    return false;
}


EDIT: Ok, obrigado por suas respostas. Especialmente para Damien Pollet e Noldorin, você me fez repensar meu design para não testar mais interfaces.

sebastiangeiger
fonte
3
Você não pode simplesmente tentar converter e capturar a exceção se for lançada (ou verificar se há um resultado nulo mesmo, se Java tiver algo análogo ao operador C # "como")? Sou um codificador C # em vez de um Java, por isso estou apenas tentando adivinhar aqui, apesar de pensar que essa abordagem seria possível em qualquer linguagem OO.
Noldorin
1
Lançar exceções é uma boa prática neste caso apenas se você não precisar se preocupar com o desempenho.
Rafa
1
Perdoe-me, mas onde essas respostas fizeram você repensar seu design? Mesmo se eles excluíssem, o que eram? Você poderia por favor me ajude @sebastiangeiger
ozanmuyes
1
@ozanmuyes Sinto muito, não escrevo Java há mais de 4 anos e, infelizmente, não me lembro do que fiz.
26416 sebastiangeiger

Respostas:

191

O instanceofoperador faz o trabalho de NullPointerExceptionmaneira segura. Por exemplo:

 if ("" instanceof java.io.Serializable) {
     // it's true
 }

produz verdadeiro. Desde a:

 if (null instanceof AnyType) {
     // never reached
 }

produz false, o instanceofoperador é nulo seguro (o código que você postou não é).

instanceof é a alternativa segura e compilada em tempo de compilação para a classe # isInstance (Object)

dfa
fonte
5
instanceof só funciona em literais de classe. Portanto, não pode ser usado no caso do OP
LordOfThePigs
certamente, é seguro em tempo de compilação; e é o built-in maneira e é o argumento da questão (IMHO)
dfa
@LordOfThePigs não, não. Ele verifica se uma interface também está implementada.
NimChimpsky
5
@NimChimpsky: você não entendeu meu argumento. Literais de classe é quando você escreve coisas como MyClass.classou MyInterface.classno seu código-fonte. Literais de classe podem se referir a classes, interfaces e tipos primitivos e retornarão uma instância correspondente à classe Class. Meu argumento é que o OP não está usando um literal de classe, mas uma instância da classe Class e, infelizmente, o operador do lado direito da instanceofpalavra - chave deve ser um literal de classe, não uma instância da classe Class.
LordOfThePigs
@dsdsdsdsd Desde este post, eu nem ouvi / li sobre ele, mas depois de procurar no Google, descobri que é a abreviação de Exceção de ponteiro nulo.
Ozanmuyes
42

Isso deve fazer:

public static boolean implementsInterface(Object object, Class interf){
    return interf.isInstance(object);
}

Por exemplo,

 java.io.Serializable.class.isInstance("a test string")

avalia como true.

Luke Woodward
fonte
8

Eu prefiro instanceof:

if (obj instanceof SomeType) { ... }

que é muito mais comum e legível do que SomeType.isInstance(obj)

Steve Kuo
fonte
5
Lembre-se de que if (obj instanceof SomeType) { ... }é estático (isto é - não pode mudar em tempo de execução) e SomeType.isInstance(obj)é dinâmico.
Tomasz Bielaszewski
4

Essa foi fácil :

   interf.isInstance(object)
Andreas Petersson
fonte
3

Se você deseja testar as interfaces:

public List<myType> getElement(Class<?> clazz) {
    List<myType> els = new ArrayList<myType>();
    for (myType e: this.elements.values()) {
        if (clazz.isAssignableFrom(e.getClass())) {
            els.add(e);
        }
    }
    return els;

}

clazz é uma interface e myType é um tipo que você definiu que pode implementar várias interfaces. Com esse código, você obtém apenas os tipos que implementam uma interface definida

Rafa
fonte
1

Eu tive esse problema hoje à noite com o Android e, depois de analisar as soluções javadoc, criei essa solução de trabalho real apenas para pessoas como eu que precisam de um pouco mais do que uma explicação sobre o javadoc.

Aqui está um exemplo de trabalho com uma interface real usando java android. Ele verifica a atividade chamada implementada na interface AboutDialogListener antes de tentar converter o campo AboutDialogListener.

public class About extends DialogFragment implements OnClickListener,
    OnCheckedChangeListener {

public static final String FIRST_RUN_ABOUT = "com.gosylvester.bestrides.firstrunabout";


public interface AboutDialogListener {
    void onFinishEditDialog(Boolean _Checked);
}

private AboutDialogListener adl;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    Activity a = this.getActivity();
    if (AboutDialogListener.class.isInstance(a)) {
        adl = (AboutDialogListener) a;
        }
}

... Mais tarde, verifico se o campo adl é! Null antes de chamar a interface

@Override
public void onStop() {
    super.onStop();
    sharedPref.edit().putBoolean(About.FIRST_RUN_ABOUT, _Checked).commit();
    // if there is an interface call it.
    if (adl != null) {
        adl.onFinishEditDialog(is_Checked());
    }
}
danny117
fonte
0

Com o Apache commons-lang ArrayUtils, verifique se a interface necessária está contida nas interfaces do seu objeto

public static Boolean implementsInterface(Object object, Class interf){
    return ArrayUtils.contains(object.getClass().getInterfaces(), interf);
}
ThePoltergeist
fonte