W3docs

Оператор instanceof в Java

Проверяйте тип объекта во время выполнения с помощью instanceof и используйте сопоставление с образцом для лаконичного кода.

instanceof задаёт вопрос во время выполнения: «действительно ли эта ссылка является T (или подтипом T)?» Ответ — boolean, а современная форма с сопоставлением с образцом также привязывает значение к типизированной переменной за один шаг, что избавляет от необходимости отдельного приведения типа.

Это инструмент, к которому обращаются, когда есть полиморфная ссылка и нужно выяснить, каким конкретным типом она является в действительности — как правило, внутри equals, при обходе гетерогенной структуры данных или при работе с запечатанными иерархиями.

Базовая форма

Классический синтаксис: expression instanceof Type:

Object o = "hello";
if (o instanceof String) {
  String s = (String) o;
  System.out.println(s.length());
}

Проверка возвращает true, если o ссылается на String или любой её подтип, и false, если o равно null или указывает на объект другого типа. null instanceof Anything всегда false — небольшая, но полезная гарантия.

Сопоставление с образцом для instanceof

Начиная с Java 16, instanceof принимает шаблон типа, объявляющий переменную, привязанную к суженному типу, прямо в том же выражении:

if (o instanceof String s) {
  System.out.println(s.length());   // no cast needed
}

Если проверка успешна, s находится в области видимости и уже типизирована как String. Если нет — s вне области видимости. Приведение типа исчезает, избыточность исчезает, и нельзя случайно привести то, что проверка отвергла.

Область видимости привязанной переменной

Привязанная переменная находится в области видимости везде, где компилятор может доказать, что проверка прошла успешно. Это включает ветку if, а также распространяется через && и в отрицание if:

if (o instanceof String s && s.length() > 3) { ... }   // s is in scope after && — also a String

if (!(o instanceof String s)) return;
System.out.println(s.length());   // s is in scope after the early return

Второй шаблон особенно удобен для кода в стиле guard-clause — сузить тип, выйти, если не совпало, и свободно использовать привязанное имя ниже.

Обратная сторона — ||: привязка не распространяется через него, потому что правая часть выполняется именно тогда, когда проверка провалилась. o instanceof String s || s.length() > 0 не скомпилируется — s не находится в области видимости справа от ||.

Ограничения на целевой тип

Компилятор отклоняет проверки, которые он может доказать невозможными. "hello" instanceof Integer даже не скомпилируется, потому что String и Integer не связаны между собой. Это позволяет обнаруживать опечатки и остатки рефакторинга во время сборки, а не во время выполнения.

Также отклоняются повышающие приведения, которые не могут завершиться неудачей: Object o = ...; if (o instanceof Object) {} помечается как избыточное.

В switch

Тот же механизм сопоставления с образцом доступен в switch, где он действительно раскрывается при работе с запечатанными иерархиями:

String describe(Object o) {
  return switch (o) {
    case Integer i  -> "int " + i;
    case String  s  -> "str of length " + s.length();
    case int[]   a  -> "array of " + a.length;
    case null       -> "nothing";
    default         -> "something else";
  };
}

При использовании запечатанного типа в качестве селектора можно убрать default, и компилятор потребует case для каждого разрешённого подтипа — совместите это с запечатанными классами, чтобы получить исчерпывающий анализ вариантов.

Когда использовать — и когда не стоит

Используйте instanceof, когда тип действительно неизвестен и ответ меняет поведение: при реализации equals, обработке запечатанных иерархий с тегированными объединениями, обходе узлов AST. Не используйте его как замену полноценного полиморфизма — цепочка if (x instanceof A) ... else if (x instanceof B) ... над открытой иерархией обычно сигнализирует о том, что виртуальный метод на типе справился бы лучше.

Рабочий пример

java— editable, runs on the server

Что дальше

instanceof — один из нескольких методов, на которые отвечает каждый объект Java. Следующая глава даёт более широкий взгляд на весь пакет — java.lang.Object, корневой класс, который каждый тип молча расширяет, и методы, которые вы наследуете от него, хотите вы того или нет. Продолжите с класса Object в Java.

Практика

Практика
Что сопоставление с образцом для `instanceof` (`if (o instanceof String s)`) позволяет не делать по сравнению с классической формой?
Что сопоставление с образцом для `instanceof` (`if (o instanceof String s)`) позволяет не делать по сравнению с классической формой?
Was this page helpful?