Operator „instanceof” zachowuje się inaczej w przypadku interfejsów i klas

88

Chciałbym wiedzieć, jak zachować się instanceofoperator w Javie.

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

Dlaczego tak się dzieje? Nie ma związku między interface Ci class B, ale daje fałsz, podczas gdy w przypadku obj instanceof Adaje błąd kompilatora?

Ajay Sharma
źródło
12
Uwaga: jeśli zmienisz to na Object obj = new B(), kompiluje się.
user253751
1
Co mówi błąd kompilatora?
karfau,
Jeśli class Bjest finalto obj instanceof Crównież nie zostanie skompilowane, ponieważ jeśli nie Bmoże mieć żadnych podtypów, to na pewno nie będzie związane z C.
jaco0646

Odpowiedzi:

127

Ponieważ Java nie ma dziedziczenia wielu klas, podczas kompilacji absolutnie wiadomo, że objobiekt typu Bnie może być podtypem A. Z drugiej strony może to być podtyp interfejsu C, na przykład w tym przypadku:

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

Zatem patrząc tylko na obj instanceof Ckompilator wyrażeń nie można z góry stwierdzić, czy będzie to prawda, czy fałsz, ale patrząc na obj instanceof Aniego, wiemy, że jest to zawsze fałszywe, a zatem bez znaczenia i pomaga zapobiec błędom. Jeśli nadal chcesz mieć to bezsensowne sprawdzenie w swoim programie, możesz dodać jawne rzutowanie do Object:

System.out.println(((Object)obj) instanceof A);      //compiles fine
Tagir Valeev
źródło
1
Innym posmakiem bezsensownego czeku jest użycieA.class.isAssignableFrom(obj.getClass())
David Ehrmann,
Jestem nieco mylić z wyjaśnieniem powiedziałeś Java has no multiple class inheritancetak zgadzam się, ale jak to jest stosowane w tym przypadku, ponieważ ani B lub A rozciąga anyting więc dlaczego wielokrotne Dziedziczenie here.It byłoby pomocne, jeśli można to wytłumaczyć?
codegasmer
@codegasmer Późna odpowiedź: Jeśli Java zezwala klasie na dziedziczenie z wielu innych klas, można by zrobić „klasa D rozszerza A, B” lub coś podobnego, a następnie „B obj = new D ()” i sprawić, że „obj instancja A ”w pierwotnym pytaniu kompiluje się (podczas gdy obecnie nie jest) - w rzeczywistości powinna lepiej się skompilować, ponieważ oczekuje się, że zostanie oceniona jako prawda. Ale jeśli po prostu nie jest dozwolone, aby cokolwiek było zarówno B, jak i A, wówczas wyrażenie „obj instanceof A”, w którym obj jest zdefiniowane jako typ B, można rozsądnie uznać za bezsensowne.
mjwach
„Jeśli nadal chcesz mieć to bezsensowne sprawdzenie” - nie musi być bez znaczenia, jakby te klasy pochodziły z innej biblioteki / frameworka, wtedy jest szansa, że ​​będziesz używać innej wersji w czasie wykonywania, w którym B extends A. W moim życiu naprawdę potrzebowałem robić takie dziwne kontrole i rzucania, jak (A)(Object)bw czasie wykonywania, tak naprawdę było to możliwe.
GotoFinal
1

Użycie finalmodyfikatora w poniższej deklaracji klasy gwarantuje, że nie może istnieć podklasa Test, która może implementować interfejs Foobar. W takim przypadku jest oczywiste, że Testi Foobarnie są ze sobą kompatybilne:

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

W przeciwnym razie, jeśli Testnie zostanie zadeklarowane final, może się zdarzyć, że podklasa Testimplementuje interfejs. I dlatego kompilator dopuściłby instrukcję test instanceof Foobarw tym przypadku.

Nurettin Armutcu
źródło