Upcasting y Downcasting
Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy. Lección 30 de 87.
En la lección anterior, viste cómo una variable de tipo padre puede contener un objeto hijo: Animal myPet = new Dog(). Esta asignación se denomina upcasting y ocurre automáticamente porque un Dog siempre es un Animal.
La conversión ascendente sube en la jerarquía de herencia. Es implícita y siempre segura:
Dog dog = new Dog();
Animal animal = dog; // Upcasting - automáticoCuando haces un upcast, solo puedes acceder a los métodos definidos en la clase padre. Los métodos específicos del hijo quedan ocultos, aunque el objeto siga siendo un Dog subyacente.
La conversión descendente va en la dirección opuesta: convierte una referencia al padre de nuevo en un tipo hijo. Esto requiere una conversión explícita porque no siempre es segura:
Animal animal = new Dog(); // Upcasting
Dog dog = (Dog) animal; // Downcasting - se requiere un cast explícito
dog.bark(); // Ahora podemos acceder a los métodos de DogLa conversión a un tipo más específico es arriesgada. Si el objeto no es realmente del tipo al que intentas convertirlo, Java lanza una ClassCastException durante la ejecución:
Animal animal = new Cat();
Dog dog = (Dog) animal; // ¡Compila, pero falla en tiempo de ejecución!El compilador no puede detectar este error porque solo ve los tipos declarados. El tipo real del objeto solo se conoce cuando se ejecuta el programa. En la próxima lección, aprenderás a comprobar de forma segura el tipo de un objeto antes de realizar una conversión descendente.
Desafío
FácilConstruyamos un sistema de reproductor multimedia que demuestre tanto el upcasting como el downcasting en acción. Crearás una jerarquía de tipos multimedia y practicarás la conversión entre referencias de clases padre e hijas.
Organizarás tu código en cuatro archivos:
Media.java: Crea la clase base que comparten todos los tipos multimedia. Cada elemento multimedia tiene un campotitle(String). Incluye un constructor para inicializarlo, un método gettergetTitle()y un métodoplay()que imprime:Playing: [title]Song.java: Crea una clase que extienda Media. Las canciones tienen un campo adicionalartist(String). Usasuperpara la inicialización de la clase padre. Sobrescribeplay()para imprimir:Playing song: [title] by [artist]. Añade un métodoshowArtist()que imprime:Artist: [artist]Podcast.java: Crea otra clase que extienda Media. Los podcasts tienen un campoepisode(int). Sobrescribeplay()para imprimir:Playing podcast: [title] - Episode [episode]. Añade un métodoshowEpisode()que imprime:Episode: [episode]Main.java: Demuestra el upcasting y el downcasting con tus tipos multimedia. Recibirás cuatro entradas: el título de una canción, el nombre de un artista, el título de un podcast y un número de episodio.Primero, crea un Song y haz upcasting a una referencia Media. Llama a
play()en esta referencia para observar la polimorfía en tiempo de ejecución.Después, haz downcasting de esa referencia Media nuevamente a Song y llama a
showArtist()para acceder al método específico de la clase hija.Luego, crea un Podcast y haz upcasting a una referencia Media. Llama a
play()en esta referencia.Finalmente, haz downcasting de esa referencia Media nuevamente a Podcast y llama a
showEpisode().
Recibirás cuatro entradas: el título de la canción (String), el nombre del artista (String), el título del podcast (String) y el número de episodio (int).
Tu salida debe mostrar cuatro líneas: dos para la canción (su salida de reproducción y la información del artista) y dos para el podcast (su salida de reproducción y la información del episodio). ¡Observa cómo el upcasting te permite tratar diferentes tipos multimedia de manera uniforme, mientras que el downcasting te permite acceder a sus características únicas!
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 songTitle = scanner.nextLine();
String artistName = scanner.nextLine();
String podcastTitle = scanner.nextLine();
int episodeNumber = scanner.nextInt();
// TODO: Crea un Song y haz upcast a una referencia Media
// TODO: Llama a play() en la referencia Media (demuestra polimorfismo)
// TODO: Haz downcast de la referencia Media de vuelta a Song
// TODO: Llama a showArtist() en la referencia Song
// TODO: Crea un Podcast y haz upcast a una referencia Media
// TODO: Llama a play() en la referencia Media
// TODO: Haz downcast de la referencia Media de vuelta a Podcast
// TODO: Llama a showEpisode() en la referencia Podcast
}
}
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