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 la conversión descendente puede fallar con una ClassCastException si el objeto no es realmente del tipo al que estás haciendo la conversión. El operador instanceof resuelve esto al permitirte comprobar el tipo de un objeto antes de hacer la conversión.
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 garantizar que la conversión tendrá éxito. El operador también devuelve true para los tipos principales de 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 la conversión de tipo en un solo paso usando la coincidencia de patrones:
if (animal instanceof Dog dog) {
dog.bark(); // 'dog' ya está casteado y listo para usar
}Esta sintaxis más limpia elimina la línea de conversión separada. Ten en cuenta que instanceof devuelve false al comprobarlo con null, por lo que no necesitas una comprobación de nulidad separada.
Desafío
FácilConstruyamos un sistema de inspección de vehículos que use el operador instanceof para identificar y manejar de forma segura distintos tipos de vehículos. Crearás una jerarquía de vehículos y escribirás código que compruebe 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 todos los vehículos comparten. Cada vehículo tiene un campomodel(String). Incluye un constructor para inicializarlo, un método gettergetModel()y un métodoinspect()que imprime:Inspecting vehicle: [model]Car.java: Crea una clase que extienda Vehicle. Los automóviles tienen un campo adicionalnumDoors(int). Usasuperpara la inicialización de la clase principal. Añade un métodocheckDoors()que imprima:[model] has [numDoors] doorsMotorcycle.java: Crea otra clase que extienda Vehicle. Las motocicletas tienen un campohasSidecar(boolean). Añade un métodocheckSidecar()que imprima[model] has a sidecaro[model] has no sidecarsegún el valor booleano.Main.java: ¡Aquí es dondeinstanceofse vuelve esencial! Recibirás cuatro entradas: el modelo de un automóvil, el número de puertas, el modelo de una motocicleta y si tiene un sidecar (true/false).Crea un arreglo de referencias
Vehicleque contenga un Car y una Motorcycle. Después, recorre el arreglo y, para cada vehículo:- Llama al método base
inspect() - Usa
instanceofpara comprobar si es un Car; si lo es, conviértelo de forma segura y llama acheckDoors() - Usa
instanceofpara comprobar si es una Motorcycle; si lo es, conviértelo de forma segura y llama acheckSidecar()
- Llama al método base
Recibirás cuatro entradas: el modelo del automóvil (String), el número de puertas (int), el modelo de la motocicleta (String) y has sidecar (boolean).
Tu salida debe mostrar cuatro líneas: para cada vehículo, verás su mensaje de inspección seguido de su comprobación específica del tipo. El operador instanceof garantiza que solo llames a métodos de Car en objetos que realmente sean Cars y a métodos de Motorcycle en objetos que realmente sean Motorcycles, ¡evitando cualquier ClassCastException!
Pruébalo tú mismo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Leer entradas
String carModel = scanner.nextLine();
int numDoors = Integer.parseInt(scanner.nextLine());
String motorcycleModel = scanner.nextLine();
boolean hasSidecar = Boolean.parseBoolean(scanner.nextLine());
// TODO: Crea un objeto Car con carModel y numDoors
// TODO: Crea un objeto Motorcycle con motorcycleModel y hasSidecar
// TODO: Crea un array de referencias Vehicle que contenga el Car y el Motorcycle
// TODO: Recorre el array y para cada vehículo:
// 1. Llama al método inspect()
// 2. Usa instanceof para comprobar si es un Car, luego haz downcast y llama a checkDoors()
// 3. Usa instanceof para comprobar si es un Motorcycle, luego haz downcast y llama 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 IteratorPractica por tu cuenta: Compilador de Java online