Оператор instanceof
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 31 из 87.
Предыдущий урок показал, что понижающее приведение типов может завершиться ошибкой 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, вы можете объединить проверку и приведение типов в один шаг, используя сопоставление с образцом (pattern matching):
if (animal instanceof Dog dog) {
dog.bark(); // 'dog' уже приведен к типу и готов к использованию
}Этот более чистый синтаксис устраняет отдельную строку приведения типов. Обратите внимание, что instanceof возвращает false при проверке на null, поэтому вам не нужна отдельная проверка на null.
Задание
ЛегкоДавайте создадим систему техосмотра транспортных средств, которая использует оператор instanceof для безопасной идентификации и обработки различных типов транспортных средств. Вы создадите иерархию транспортных средств и напишете код, который проверяет фактический тип каждого транспортного средства перед доступом к его специализированным функциям.
Вы организуете свой код в четырех файлах:
Vehicle.java: Создайте базовый класс, который является общим для всех транспортных средств. У каждого транспортного средства есть полеmodel(String). Добавьте конструктор для его инициализации, метод-геттерgetModel()и методinspect(), который выводит:"Inspecting vehicle: " + modelCar.java: Создайте класс, который расширяет Vehicle. У автомобилей есть дополнительное полеnumDoors(int). Используйтеsuperдля инициализации родительского класса. Добавьте методcheckDoors(), который выводит:getModel() + " has " + numDoors + " doors"Motorcycle.java: Создайте еще один класс, который расширяет Vehicle. У мотоциклов есть полеhasSidecar(boolean). Добавьте методcheckSidecar(), который выводит либоgetModel() + " has a sidecar", либоgetModel() + " has no sidecar"в зависимости от логического значения.Main.java: Здесьinstanceofстановится необходимым! Вы получите четыре входных значения: модель автомобиля, количество дверей, модель мотоцикла и наличие коляски (true/false).Создайте массив ссылок
Vehicle, содержащий Car и Motorcycle. Затем переберите массив в цикле и для каждого транспортного средства:- Вызовите базовый метод
inspect() - Используйте
instanceof, чтобы проверить, является ли объект Car — если да, выполните безопасное приведение типов (downcast) и вызовитеcheckDoors() - Используйте
instanceof, чтобы проверить, является ли объект Motorcycle — если да, выполните безопасное приведение типов (downcast) и вызовитеcheckSidecar()
- Вызовите базовый метод
Вы получите четыре входных значения: модель автомобиля (String), количество дверей (int), модель мотоцикла (String) и наличие коляски (boolean).
Ваш вывод должен содержать четыре строки — для каждого транспортного средства вы увидите сообщение об осмотре, за которым следует проверка, специфичная для данного типа. Оператор instanceof гарантирует, что вы вызываете методы Car только для объектов Car, а методы Motorcycle — только для объектов Motorcycle, предотвращая возникновение ClassCastException!
Шпаргалка
Оператор instanceof проверяет, является ли объект экземпляром определенного класса, перед выполнением приведения типов:
Animal animal = new Dog();
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.bark(); // Safe to call Dog-specific methods
}Оператор возвращает 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, сопоставление с образцом (pattern matching) объединяет проверку и приведение типов в один шаг:
if (animal instanceof Dog dog) {
dog.bark(); // 'dog' is already cast and ready to use
}Оператор instanceof возвращает false при проверке значения null, что избавляет от необходимости в отдельных проверках на null.
Попробуйте сами
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: Пройдите циклом по массиву и для каждого транспортного средства:
// 1. Вызовите метод inspect()
// 2. Используйте instanceof, чтобы проверить, является ли объект Car, затем выполните понижающее приведение типа и вызовите checkDoors()
// 3. Используйте instanceof, чтобы проверить, является ли объект Motorcycle, затем выполните понижающее приведение типа и вызовите 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
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»