Оператор instanceof
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy. Урок 31 из 87.
В предыдущем уроке было показано, что downcasting может завершиться ошибкой ClassCastException, если объект на самом деле не является типом, к которому вы выполняете приведение. Оператор instanceof решает эту проблему, позволяя проверить тип объекта перед приведением.
Синтаксис прост: object instanceof ClassName возвращает true, если объект является экземпляром этого класса (или любого из его подклассов):
Animal animal = new Dog();
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.bark(); // Безопасно вызывать методы, специфичные для Dog
}Эта проверка предотвращает ошибки во время выполнения, гарантируя, что приведение типов будет успешным. Оператор также возвращает true для родительских типов в иерархии:
Dog dog = new Dog();
System.out.println(dog instanceof Dog); // true
System.out.println(dog instanceof Animal); // true
System.out.println(dog instanceof Object); // trueНачиная с Java 16, вы можете объединить check и cast в один шаг с помощью сопоставления с образцом:
if (animal instanceof Dog dog) {
dog.bark(); // 'dog' уже приведён и готов к использованию
}Этот более чистый синтаксис устраняет отдельную строку приведения типа. Обратите внимание, что instanceof возвращает false при проверке с null, поэтому отдельная проверка на null не нужна.
Задание
ЛегкоДавайте создадим систему проверки транспортных средств, которая использует оператор instanceof для безопасного определения и обработки различных типов транспортных средств. Вы создадите иерархию транспортных средств и напишете код, который проверяет фактический тип каждого транспортного средства перед обращением к его специализированным функциям.
Вы организуете код в четырёх файлах:
Vehicle.java: Создайте базовый class, общий для всех транспортных средств. У каждого транспортного средства есть fieldmodel(String). Добавьте constructor для его инициализации, getter methodgetModel()и methodinspect(), который выводит:Inspecting vehicle: [model]Car.java: Создайте class, который расширяет Vehicle. У автомобилей есть дополнительный fieldnumDoors(int). Используйтеsuperдля инициализации родительского class. Добавьте methodcheckDoors(), который выводит:[model] has [numDoors] doorsMotorcycle.java: Создайте ещё один class, который расширяет Vehicle. У мотоциклов есть fieldhasSidecar(boolean). Добавьте methodcheckSidecar(), который в зависимости от значения boolean выводит либо[model] has a sidecar, либо[model] has no sidecar.Main.java: Здесьinstanceofстановится особенно важным! Вы получите четыре входных значения: модель автомобиля, количество дверей, модель мотоцикла и наличие бокового прицепа (true/false).Создайте array ссылок типа
Vehicle, содержащий Car и Motorcycle. Затем пройдите в цикле по array и для каждого транспортного средства:- Вызовите базовый method
inspect() - Используйте
instanceof, чтобы проверить, является ли оно Car; если да, безопасно выполните downcast и вызовитеcheckDoors() - Используйте
instanceof, чтобы проверить, является ли оно Motorcycle; если да, безопасно выполните downcast и вызовитеcheckSidecar()
- Вызовите базовый method
Вы получите четыре входных значения: модель автомобиля (String), количество дверей (int), модель мотоцикла (String) и наличие бокового прицепа (boolean).
Ваша программа должна вывести четыре строки: для каждого транспортного средства вы увидите сообщение о проверке, за которым следует проверка, специфичная для его типа. Оператор instanceof гарантирует, что вы вызываете методы Car только для настоящих Car, а методы Motorcycle — только для настоящих Motorcycle, предотвращая возникновение ClassCastException!
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Считать входные данные
String carModel = scanner.nextLine();
int numDoors = Integer.parseInt(scanner.nextLine());
String motorcycleModel = scanner.nextLine();
boolean hasSidecar = Boolean.parseBoolean(scanner.nextLine());
// TODO: Создать объект Car с carModel и numDoors
// TODO: Создать объект Motorcycle с motorcycleModel и hasSidecar
// TODO: Создать массив ссылок Vehicle, содержащий Car и Motorcycle
// TODO: Пройти по массиву и для каждого vehicle:
// 1. Вызвать метод inspect()
// 2. Использовать instanceof, чтобы проверить, является ли это Car, затем выполнить downcast и вызвать checkDoors()
// 3. Использовать instanceof, чтобы проверить, является ли это Motorcycle, затем выполнить downcast и вызвать checkSidecar()
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»Потренируйтесь самостоятельно: Онлайн-компилятор Java