O operador 'instanceof' se comporta de maneira diferente para interfaces e classes

88

Eu gostaria de saber a respeito do seguinte comportamento do instanceofoperador em Java.

interface C {}

class B {}

public class A {
    public static void main(String args[]) {
        B obj = new B();
        System.out.println(obj instanceof A);      //Gives compiler error
        System.out.println(obj instanceof C);      //Gives false as output
    }
}

Por que é tão? Não há relação entre interface Ce class B, mas dá falso enquanto que no caso de obj instanceof Adá erro do compilador?

Ajay Sharma
fonte
12
Nota: se você alterar para Object obj = new B(), ele compila.
user253751
1
O que o erro do compilador diz a você?
karfau
Se class Bfor, finalentão obj instanceof Ctambém não compilará, porque se não Bpuder ter subtipos, é garantido que ele não esteja relacionado a C.
jaco0646

Respostas:

127

Como o Java não tem herança múltipla de classes, é absolutamente conhecido durante a compilação que o objobjeto do tipo Bnão pode ser um subtipo A. Por outro lado, possivelmente pode ser um subtipo de interface C, por exemplo neste caso:

interface C {}

class B {}

class D extends B implements C {}

public class A {
    public static void main(String args[]) {
        B obj = new D();
        System.out.println(obj instanceof C);      //compiles and gives true as output  
    }
}

Portanto, olhar apenas para o obj instanceof Ccompilador de expressão não pode dizer com antecedência se será verdadeiro ou falso, mas olhar para obj instanceof Aele sabe que isso é sempre falso, portanto, sem sentido e ajuda a evitar um erro. Se você ainda deseja ter essa verificação sem sentido em seu programa, você pode adicionar uma transmissão explícita ao Object:

System.out.println(((Object)obj) instanceof A);      //compiles fine
Tagir Valeev
fonte
1
O outro sabor de um cheque sem sentido é usarA.class.isAssignableFrom(obj.getClass())
David Ehrmann
Estou um pouco confuso com a sua explicação, você disse Java has no multiple class inheritancesim, eu concordo, mas como isso é aplicado neste caso porque nem B nem A estendem nada, então por que herança múltipla aqui. Seria útil se você pudesse explicar?
codegasmer
@codegasmer Resposta tardia: Se Java permitisse que uma classe herdasse de várias outras classes, então alguém poderia fazer "class D extends A, B" ou algo assim, e então "B obj = new D ()", e fazer o "obj instanceof A "na questão original compila (enquanto atualmente não) - na verdade, é melhor compilar, porque seria esperado que fosse avaliado como verdadeiro. Mas se simplesmente não for permitido que nada seja B e A, então a expressão "instância de obj de A", em que obj é definido como tipo B, pode ser razoavelmente considerada sem sentido.
mjwach de
"Se você ainda deseja ter essa verificação sem sentido" - não precisa ser sem sentido, como se essas classes fossem de outra biblioteca / estrutura, então há chance de você usar uma versão diferente em tempo de execução onde B extends A. Na minha vida, eu realmente precisava fazer verificações e projeções estranhas, (A)(Object)bcomo no tempo de execução, era realmente possível ser verdade.
GotoFinal
1

Ao usar o finalmodificador na declaração de classe abaixo, é garantido que não poderia haver uma subclasse de Test, que pode implementar a interface Foobar. Nesse caso, é óbvio que Teste Foobarnão são compatíveis entre si:

public final class Test {

    public static void main(String[] args) {
        Test test = new Test();
        System.out.println(test instanceof Foobar); // Compiler error: incompatible types
    }
}

interface Foobar {
}

Caso contrário, se Testnão for declarado final, pode ser possível que uma subclasse de Testimplemente a interface. E é por isso que o compilador permitiria a declaração test instanceof Foobarneste caso.

Nurettin Armutcu
fonte