Оператор "instanceof" ведет себя по-разному для интерфейсов и классов

Я хотел бы узнать о следующем поведении оператора instanceof в 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
    }
}

Почему так? Между interface C и class B нет отношения, но он дает false, тогда как в случае obj instanceof A он дает ошибку компилятора?

Ответ 1

Поскольку Java не имеет наследования множественного класса, он абсолютно известен во время компиляции, что объект obj типа B не может быть подтипом A. С другой стороны, возможно, это подтип интерфейса C, например, в этом случае:

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

Поэтому, глядя только на obj instanceof C, компилятор выражения не может заранее сказать, будет ли он истинным или ложным, но, глядя на obj instanceof A, он знает, что это всегда ложно, поэтому бессмысленно и помогает предотвратить ошибку. Если вы все еще хотите иметь эту бессмысленную проверку в своей программе, вы можете добавить явное литье в Object:

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

Ответ 2

Используя модификатор final в объявлении класса ниже, гарантируется, что не может быть подкласса Test, который может реализовать интерфейс Foobar. В этом случае очевидно, что Test и Foobar несовместимы друг с другом:

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

В противном случае, если Test не объявлен final, возможно, что подкласс Test реализует интерфейс. И поэтому компилятор допустил бы оператор test instanceof Foobar в этом случае.