my.life.logging.Blog

Java: использование оператора Instanceof с интерфейсом

a.k.a. Особенности использования оператора instanceof для проверки реализации объектом интерфейса в языке Java. Ведь, наверняка, кому-то длинные заголовки нравятся больше. :)

Обнаружил один интересный момент, касающийся реализации оператора instanceof в Java, о котором редко где упоминают.

Все мы знаем, что попытки использования в операторе instanceof типов, не входящих в одну иерархию наследования, резко пресекаются компилятором. Так, например, следующий код:

Class1.java
1
2
3
4
5
6
7
8
9
public class Class1 {
  public static void main(String[] args) {
    Class1 class1 = new Class1();
    System.out.println(class1 instanceof Class2);
  }
}

class Class2 {
}

приведет к ошибке компиляции:

1
2
3
4
Class1.java:4: inconvertible types
found   : Class1
required: Class2
        System.out.println(class1 instanceof Class2);

Но, оказывается, так бывает не всегда. Давайте заменим класс в правой части оператора instanceof каким-либо интерфейсом:

Class1.java
1
2
3
4
5
6
7
8
9
public class Class1 {
  public static void main(String[] args) {
    Class1 class1 = new Class1();
    System.out.println(class1 instanceof Interface1);
  }
}

interface Interface1 {
}

Как ни странно, в этом случае компиляция проходит вполне успешно! И, к слову, скомпилированная программа выполняется вообще без каких-либо проблем и выводит результат “false” в консоль.

Постарайтесь не спешить с выводами, так как если мы перепишем наш пример следующим образом:

Class1.java
1
2
3
4
5
6
7
8
9
public class Class1 {
  public static void main(String[] args) {
    String s = "";
    System.out.println(s instanceof Interface1);
  }
}

interface Interface1 {
}

то это вновь приведет к ошибке компиляции! То есть практически той же самой, что и в первом случае:

1
2
3
4
Class1.java:4: inconvertible types
found   : java.lang.String
required: Interface1
        System.out.println(s instanceof Interface1);

Забавно, не правда ли?

На самом деле, все дело в том, что String – это финальный класс, в отличие от нашего класса Class1. В случае, если класс объявлен с модификатором final, компилятору удается определить, реализует ли класс какой-либо интерфейс или нет. Во всех остальных случаях компилятор сделать это не в состоянии, так как интерфейс может реализовывать один из потомков данного класса. Да, не слишком убедительное оправдание, на мой взгляд, но, тем не менее, “такова жизнь, сынок”.

Думаю, знание о подобном поведении оператора instanceof пригодится программистам, готовящимся к прохождению Java-сертификации. Как раз-таки использование оператора instanceof с интерфейсом было предметом одного из каверзных вопросов, встреченных мною во время подготовки к OCPJP.

 

Comments