L'operatore "instanceof" si comporta in modo diverso per interfacce e classi


88

Vorrei sapere riguardo al seguente comportamento instanceofdell'operatore in 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
    }
}

Perché è così? Non c'è relazione tra interface Ce class B, ma dà falso mentre in caso di obj instanceof Aerrore del compilatore?


12
Nota: se lo cambi in Object obj = new B(), viene compilato.
user253751

1
Cosa ti dice l'errore del compilatore?
karfau

If class Bis finalthen obj instanceof Cnon verrà compilato, perché se non Bpuò avere sottotipi, è garantito che non sarà correlato a C.
jaco0646

Risposte:


127

Poiché Java non ha ereditarietà di classi multiple, durante la compilazione è assolutamente noto che l' objoggetto di tipo Bnon può essere un sottotipo di A. D'altra parte può essere un sottotipo di interfaccia C, ad esempio in questo 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  
    }
}

Quindi guardando solo al obj instanceof Ccompilatore di espressioni non è possibile dire in anticipo se sarà vero o falso, ma guardandolo obj instanceof Asi sa che questo è sempre falso, quindi privo di significato e aiuta a prevenire un errore. Se vuoi ancora avere questo controllo senza senso nel tuo programma, puoi aggiungere un casting esplicito a Object:

System.out.println(((Object)obj) instanceof A);      //compiles fine

1
L'altro sapore di un controllo senza senso è usareA.class.isAssignableFrom(obj.getClass())
David Ehrmann

Sono un po 'confuso con la tua spiegazione, hai detto di Java has no multiple class inheritancesì, sono d'accordo, ma come viene applicato in questo caso perché né B né A estendono nulla, quindi perché l'ereditarietà multipla qui Sarebbe utile se puoi spiegare?
codegasmer

@codegasmer Risposta tardiva: se Java consentisse a una classe di ereditare da più altre classi, allora si potrebbe fare "la classe D estende A, B" o qualcosa del genere, quindi "B obj = new D ()", e fare il "obj instanceof A "nella domanda originale si compila (mentre attualmente non lo fa) - in effetti è stato meglio compilare, perché ci si aspetterebbe che restituisca true. Ma se semplicemente non è permesso che qualcosa sia sia B che A, allora l'espressione "obj istanza di A" dove obj è definito come tipo B può essere ragionevolmente considerata priva di senso.
mjwach

"Se vuoi ancora avere questo controllo senza senso" - non è necessario che sia privo di significato, come se queste classi provenissero da un'altra libreria / framework, allora c'è la possibilità che utilizzerai una versione diversa in fase di runtime dove B extends A. Nella mia vita avevo davvero bisogno di fare controlli e lanci così strani come (A)(Object)bse in runtime fosse possibile essere vero.
GotoFinal

1

Utilizzando il finalmodificatore nella dichiarazione di classe di seguito, è garantito che non potrebbe esserci una sottoclasse di Test, che potrebbe implementare l'interfaccia Foobar. In questo caso è ovvio che Teste Foobarnon sono compatibili tra loro:

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 {
}

Altrimenti, se Testnon viene dichiarato final, potrebbe essere possibile che una sottoclasse di Testimplementa l'interfaccia. Ed è per questo che il compilatore consentirebbe l'istruzione test instanceof Foobarin questo caso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.