«1. Введение

В этом кратком руководстве мы узнаем об операторе instanceof в Java.

2. Что такое instanceof Operator?

instanceof — это бинарный оператор, используемый для проверки того, принадлежит ли объект заданному типу. Результат операции либо истина, либо ложь. Он также известен как оператор сравнения типов, поскольку сравнивает экземпляр с типом.

Перед приведением неизвестного объекта всегда следует использовать проверку instanceof. Это помогает избежать ClassCastException во время выполнения.

Основной синтаксис оператора instanceof:

(object) instanceof (type)

Давайте рассмотрим простой пример оператора instanceof. Во-первых, давайте создадим класс Round:

public class Round {
    // implementation details
}

Затем давайте создадим класс Ring, который расширяет Round:

public class Ring extends Round {
    // implementation details
}

Мы можем использовать instanceof, чтобы проверить, относится ли экземпляр Ring к типу Round:

@Test
public void givenWhenInstanceIsCorrect_thenReturnTrue() {
    Ring ring = new Ring();
    Assert.assertTrue(ring instanceof Round);
}

3. Как работает оператор instanceof?

Оператор instanceof работает по принципу отношения is-a. Концепция отношения is-a основана на наследовании классов или реализации интерфейса.

Чтобы продемонстрировать это, давайте создадим интерфейс Shape:

public interface Shape {
    // implementation details
}

Давайте также создадим класс Circle, который реализует интерфейс Shape, а также расширяет класс Round:

public class Circle extends Round implements Shape {
    // implementation details
}

Результат instanceof будет истинным, если объект является экземпляром типа:

@Test
public void givenWhenObjectIsInstanceOfType_thenReturnTrue() {
    Circle circle = new Circle();
    Assert.assertTrue(circle instanceof Circle);
}

Также будет true, если объект является экземпляром подкласса типа:

@Test
public void giveWhenInstanceIsOfSubtype_thenReturnTrue() {
    Circle circle = new Circle();
    Assert.assertTrue(circle instanceof Round);
}

Если тип является интерфейсом, он вернет true если объект реализует интерфейс:

@Test
public void givenWhenTypeIsInterface_thenReturnTrue() {
    Circle circle = new Circle();
    Assert.assertTrue(circle instanceof Shape);
}

Оператор instanceof нельзя использовать, если нет связи между сравниваемым объектом и типом, с которым он сравнивается.

Давайте создадим новый класс Triangle, который реализует Shape, но не имеет отношения к Circle:

public class Triangle implements Shape {
    // implementation details
}

Теперь, если мы используем instanceof, чтобы проверить, является ли Circle экземпляром Triangle:

@Test
public void givenWhenComparingClassInDiffHierarchy_thenCompilationError() {
    Circle circle = new Circle();
    Assert.assertFalse(circle instanceof Triangle);
}

Мы Вы получите ошибку компиляции, потому что между классами Circle и Triangle нет связи:

java.lang.Error: Unresolved compilation problem:
  Incompatible conditional operand types Circle and Triangle

4. Использование instanceof с типом объекта

В Java каждый класс неявно наследуется от класса Object. Следовательно, использование оператора instanceof с типом Object всегда будет оцениваться как true:

@Test
public void givenWhenTypeIsOfObjectType_thenReturnTrue() {
    Thread thread = new Thread();
    Assert.assertTrue(thread instanceof Object);
}

5. Использование оператора instanceof, когда объект имеет значение null

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

@Test
public void givenWhenInstanceValueIsNull_thenReturnFalse() {
    Circle circle = null;
    Assert.assertFalse(circle instanceof Round);
}

6. instanceof и Generics

Тесты и приведения экземпляров зависят от проверки информации о типе во время выполнения. Поэтому мы не можем использовать instanceof вместе со стертыми универсальными типами.

Например, если мы попытаемся скомпилировать следующий фрагмент:

public static <T> void sort(List<T> collection) {
    if (collection instanceof List<String>) {
        // sort strings differently
    }
        
    // omitted
}

Тогда мы получим эту ошибку компиляции:

error: illegal generic type for instanceof
        if (collection instanceof List<String>) {
                                      ^

С технической точки зрения, мы можем использовать instanceof только вместе с овеществленными типами в Java. . Тип овеществляется, если информация о его типе присутствует во время выполнения.

Овеществленные типы в Java следующие:

    Примитивные типы, такие как int Неуниверсальные классы и интерфейсы, такие как String или Random Универсальные типы, в которых все типы являются неограниченными подстановочными знаками, такими как Set\u003c?\u003e или Map\u003c?, ?\u003e Необработанные типы, такие как List или HashMap Массивы других реализуемых типов, таких как String[], List[] или Map\u003c?, ?\u003e[]

Поскольку параметры универсального типа не овеществлены, мы также не можем их использовать: ~ ~~

public static <T> boolean isOfType(Object input) {
    return input instanceof T; // won't compile
}

Однако можно протестировать что-то вроде List\u003c?\u003e:

if (collection instanceof List<?>) {
    // do something
}

7. Заключение

В этом уроке мы узнали об операторе instanceof и о том, как его использовать. Полные образцы кода доступны на GitHub.