El operador instanceof
Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 31 de 87.
La lección anterior mostró que el downcasting puede fallar con una ClassCastException si el objeto no es realmente del tipo al que estás realizando el casting. El operador instanceof resuelve esto permitiéndote comprobar el tipo de un objeto antes de realizar el casting.
La sintaxis es sencilla: object instanceof ClassName devuelve true si el objeto es una instancia de esa clase (o de cualquiera de sus subclases):
Animal animal = new Dog();
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.bark(); // Es seguro llamar a métodos específicos de Dog
}Esta comprobación evita errores en tiempo de ejecución al asegurar que la conversión (cast) tendrá éxito. El operador también devuelve true para los tipos padre en la jerarquía:
Dog dog = new Dog();
System.out.println(dog instanceof Dog); // true
System.out.println(dog instanceof Animal); // true
System.out.println(dog instanceof Object); // trueDesde Java 16, puedes combinar la comprobación y el moldeado (cast) en un solo paso utilizando la coincidencia de patrones (pattern matching):
if (animal instanceof Dog dog) {
dog.bark(); // 'dog' ya está convertido y listo para usar
}Esta sintaxis más limpia elimina la línea de conversión separada. Ten en cuenta que instanceof devuelve false cuando se prueba contra null, por lo que no necesitas una comprobación de nulos separada.
Desafío
FácilVamos a construir un sistema de inspección de vehículos que utiliza el operador instanceof para identificar y manejar de forma segura diferentes tipos de vehículos. Crearás una jerarquía de vehículos y escribirás código que verifique el tipo real de cada vehículo antes de acceder a sus funciones especializadas.
Organizarás tu código en cuatro archivos:
Vehicle.java: Crea la clase base que comparten todos los vehículos. Cada vehículo tiene un campomodel(String). Incluye un constructor para inicializarlo, un método gettergetModel()y un métodoinspect()que imprima:"Inspecting vehicle: " + modelCar.java: Crea una clase que extienda de Vehicle. Los coches tienen un campo adicionalnumDoors(int). Usasuperpara la inicialización del padre. Añade un métodocheckDoors()que imprima:getModel() + " has " + numDoors + " doors"Motorcycle.java: Crea otra clase que extienda de Vehicle. Las motocicletas tienen un campohasSidecar(boolean). Añade un métodocheckSidecar()que imprimagetModel() + " has a sidecar"ogetModel() + " has no sidecar"dependiendo del valor booleano.Main.java: ¡Aquí es dondeinstanceofse vuelve esencial! Recibirás cuatro entradas: un modelo de coche, el número de puertas, un modelo de motocicleta y si tiene sidecar (true/false).Crea un array de referencias de
Vehicleque contenga un Car y una Motorcycle. Luego, recorre el array y para cada vehículo:- Llama al método base
inspect() - Usa
instanceofpara verificar si es un Car; si es así, realiza un downcast seguro y llama acheckDoors() - Usa
instanceofpara verificar si es una Motorcycle; si es así, realiza un downcast seguro y llama acheckSidecar()
- Llama al método base
Recibirás cuatro entradas: el modelo del coche (String), el número de puertas (int), el modelo de la motocicleta (String) y si tiene sidecar (boolean).
Tu salida debería mostrar cuatro líneas: para cada vehículo, verás su mensaje de inspección seguido de su comprobación específica de tipo. El operador instanceof garantiza que solo llames a los métodos de Car en objetos Car reales y a los métodos de Motorcycle en Motorcycles reales, ¡evitando cualquier ClassCastException!
Hoja de referencia
El operador instanceof comprueba si un objeto es una instancia de una clase específica antes de realizar la conversión (casting):
Animal animal = new Dog();
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.bark(); // Es seguro llamar a métodos específicos de Dog
}El operador devuelve true para la clase del objeto y todas las clases padre en la jerarquía:
Dog dog = new Dog();
System.out.println(dog instanceof Dog); // true
System.out.println(dog instanceof Animal); // true
System.out.println(dog instanceof Object); // trueDesde Java 16, la coincidencia de patrones (pattern matching) combina la comprobación y la conversión en un solo paso:
if (animal instanceof Dog dog) {
dog.bark(); // 'dog' ya está convertido y listo para usar
}El operador instanceof devuelve false cuando se prueba contra null, eliminando la necesidad de realizar comprobaciones de nulos por separado.
Pruébalo tú mismo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Leer las entradas
String carModel = scanner.nextLine();
int numDoors = Integer.parseInt(scanner.nextLine());
String motorcycleModel = scanner.nextLine();
boolean hasSidecar = Boolean.parseBoolean(scanner.nextLine());
// TODO: Crear un objeto Car con carModel y numDoors
// TODO: Crear un objeto Motorcycle con motorcycleModel y hasSidecar
// TODO: Crear un arreglo de referencias de Vehicle que contenga el Car y el Motorcycle
// TODO: Recorrer el arreglo y para cada vehículo:
// 1. Llamar al método inspect()
// 2. Usar instanceof para verificar si es un Car, luego realizar un downcast y llamar a checkDoors()
// 3. Usar instanceof para verificar si es un Motorcycle, luego realizar un downcast y llamar a checkSidecar()
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a la OOPClases vs. ObjetosLa palabra clave thisMétodosCampos (Atributos)Método constructorSobrecarga de constructoresResumen - Calculadora simple4Herencia
Herencia básica (extends)La palabra clave superSobrescritura de métodos (@Override)Encadenamiento de constructoresLa clase ObjectHerencia simple y multinivelPor qué no hay herencia múltiple de clasesResumen - Jerarquía de empleados7Métodos especiales y la clase Object
Método toString()equals() y hashCode()Método clone()compareTo() y ComparableInterfaz ComparatorResumen - Ordenamiento personalizado2Modificadores de acceso y encapsulamiento
Visión general de los niveles de accesoMétodos Getter y SetterOcultamiento de informaciónLa palabra clave finalResumen - Gestor de cuentas bancarias5Polimorfismo
Fundamentos de sobrecarga de métodosSobrescritura de métodos (tiempo de ejecución)Upcasting y DowncastingEl operador instanceofClases y métodos abstractosResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaAgregación vs. ComposiciónClases internas, anidadas y anónimasEnums y métodos de EnumRecords (Java 16+)Clases selladas (Java 17+)11Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón BuilderPatrón ObserverPatrón Strategy3Propiedades de clase y miembros estáticos
Variables de instancia vs. estáticasMétodos estáticosBloques estáticosConstantes (static final)Repaso - Contador y utilidad6Interfaces y Clases Abstractas
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesMétodos Default y Static en InterfacesClases Abstractas vs InterfacesInterfaces FuncionalesResumen - Sistema de Pagos9Genéricos
Introducción a los genéricosClases genéricasMétodos genéricosParámetros de tipo delimitadosComodines (?, extends, super)Resumen - Contenedor genérico12Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Iterator