Upcasting e downcasting
Fa parte della sezione Programmazione orientata agli oggetti del percorso Java di Coddy. Lezione 30 di 87.
Nella lezione precedente, hai visto come una variabile di tipo genitore possa contenere un oggetto figlio: Animal myPet = new Dog(). Questa assegnazione è chiamata upcasting e avviene automaticamente perché un Dog è sempre un Animal.
Upcasting risale la gerarchia di ereditarietà. È implicito e sempre sicuro:
Dog dog = new Dog();
Animal animal = dog; // Upcasting - automaticoQuando esegui l'upcasting, puoi accedere solo ai metodi definiti nella classe genitore. I metodi specifici della classe figlia diventano nascosti, anche se l'oggetto sottostante è ancora un Dog.
Downcasting procede nella direzione opposta, convertendo un riferimento al genitore di nuovo in un tipo figlio. Questo richiede un cast esplicito perché non è sempre sicuro:
Animal animal = new Dog(); // Upcasting
Dog dog = (Dog) animal; // Downcasting - è necessario un cast esplicito
dog.bark(); // Ora possiamo accedere ai metodi di DogIl downcasting è rischioso. Se l'oggetto non è effettivamente del tipo in cui lo stai convertendo, Java genera una ClassCastException in fase di esecuzione:
Animal animal = new Cat();
Dog dog = (Dog) animal; // Si compila, ma va in errore durante l'esecuzione!Il compilatore non può rilevare questo errore perché vede solo i tipi dichiarati. Il tipo effettivo dell'oggetto si conosce solo quando il programma viene eseguito. Nella prossima lezione imparerai a verificare in sicurezza il tipo di un oggetto prima di eseguire il downcasting.
Sfida
FacileCostruiamo un sistema di riproduzione multimediale che dimostri in azione sia l'upcasting sia il downcasting. Creerai una gerarchia di tipi multimediali e farai pratica convertendo i riferimenti tra classi padre e figlie.
Organizzerai il codice in quattro file:
Media.java: crea la classe base condivisa da tutti i tipi multimediali. Ogni elemento multimediale ha un campotitle(String). Includi un costruttore per inizializzarlo, un metodo gettergetTitle()e un metodoplay()che stampa:Playing: [title]Song.java: crea una classe che estende Media. Le canzoni hanno un campo aggiuntivoartist(String). Usasuperper inizializzare la classe padre. Sovrascriviplay()affinché stampi:Playing song: [title] by [artist]. Aggiungi un metodoshowArtist()che stampa:Artist: [artist]Podcast.java: crea un'altra classe che estende Media. I podcast hanno un campoepisode(int). Sovrascriviplay()affinché stampi:Playing podcast: [title] - Episode [episode]. Aggiungi un metodoshowEpisode()che stampa:Episode: [episode]Main.java: dimostra l'upcasting e il downcasting con i tuoi tipi multimediali. Riceverai quattro input: il titolo di una canzone, il nome di un artista, il titolo di un podcast e il numero dell'episodio.Per prima cosa, crea un Song ed esegui l'upcasting a un riferimento Media. Chiama
play()su questo riferimento per vedere in azione il polimorfismo in fase di esecuzione.Poi, esegui il downcasting di quel riferimento Media di nuovo a Song e chiama
showArtist()per accedere al metodo specifico della classe figlia.Quindi, crea un Podcast ed esegui l'upcasting a un riferimento Media. Chiama
play()su questo riferimento.Infine, esegui il downcasting di quel riferimento Media di nuovo a Podcast e chiama
showEpisode().
Riceverai quattro input: il titolo della canzone (String), il nome dell'artista (String), il titolo del podcast (String) e il numero dell'episodio (int).
Il tuo output dovrebbe mostrare quattro righe: due per la canzone (il risultato di play e le informazioni sull'artista) e due per il podcast (il risultato di play e le informazioni sull'episodio). Nota come l'upcasting ti permette di trattare in modo uniforme diversi tipi multimediali, mentre il downcasting ti permette di accedere alle loro caratteristiche specifiche!
Provalo tu
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Leggi gli input
String songTitle = scanner.nextLine();
String artistName = scanner.nextLine();
String podcastTitle = scanner.nextLine();
int episodeNumber = scanner.nextInt();
// TODO: Crea un Song ed esegui un upcast a un riferimento Media
// TODO: Chiama play() sul riferimento Media (dimostra il polimorfismo)
// TODO: Esegui un downcast del riferimento Media a Song
// TODO: Chiama showArtist() sul riferimento Song
// TODO: Crea un Podcast ed esegui un upcast a un riferimento Media
// TODO: Chiama play() sul riferimento Media
// TODO: Esegui un downcast del riferimento Media a Podcast
// TODO: Chiama showEpisode() sul riferimento Podcast
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione a oggetti
File esterniIntroduzione alla programmazione a oggettiClassi e oggettiLa parola chiave thisMetodiCampi (attributi)Metodo costruttoreSovraccarico dei costruttoriRipasso - Calcolatrice semplice4Ereditarietà
Ereditarietà di base (extends)La parola chiave superSovrascrittura dei metodi (@Override)Concatenamento dei costruttoriLa classe ObjectEreditarietà singola e multilivelloPerché non esiste l'ereditarietà multipla delle classiRiepilogo: gerarchia dei dipendenti7Metodi speciali e classe Object
Metodo toString()equals() e hashCode()Metodo clone()compareTo() e ComparableInterfaccia ComparatorRiepilogo - Ordinamento personalizzato2Modificatori di accesso e incapsulamento
Panoramica dei livelli di accessoMetodi getter e setterNascondimento delle informazioniLa parola chiave finalRiepilogo - Gestore di conti bancari5Polimorfismo
Nozioni di base sull'overloading dei metodiOverride dei metodi (a runtime)Upcasting e downcastingL'operatore instanceofClassi e metodi astrattiRiepilogo - Calcolatore di forme8Concetti avanzati di OOP
Composizione vs ereditarietàAggregazione vs composizioneClassi interne, annidate e anonimeEnum e metodi degli EnumRecord (Java 16+)Classi sealed (Java 17+)11Modelli di progettazione Parte 1
Introduzione ai modelli di progettazionePattern SingletonPattern FactoryPattern BuilderPattern ObserverPattern Strategy3Proprietà di classe e membri statici
Variabili di istanza e staticheMetodi staticiBlocchi staticiCostanti (static final)Riepilogo - Contatore e utility6Interfacce e classi astratte
Introduzione alle interfacceImplementazione delle interfacceImplementazione di più interfacceMetodi default e static nelle interfacceClassi astratte e interfacce a confrontoInterfacce funzionaliRiepilogo: sistema di pagamento9Tipi generici
Introduzione ai tipi genericiClassi genericheMetodi genericiParametri di tipo con limitiCaratteri jolly (?, extends, super)Riepilogo - Contenitore generico12Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositePattern IteratorEsercitati da solo: Compilatore Java online