Menu
Coddy logo textTech

Upcasting e Downcasting

Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 30 de 87.

Na lição anterior, você viu como uma variável do tipo pai pode conter um objeto filho: Animal myPet = new Dog(). Essa atribuição é chamada de upcasting, e ela acontece automaticamente porque um Dog é sempre um Animal.

Upcasting sobe na hierarquia de herança. É implícito e sempre seguro:

Dog dog = new Dog();
Animal animal = dog;  // Upcasting - automático

Quando você realiza o upcasting, você só pode acessar métodos definidos na classe pai. Os métodos específicos da classe filha tornam-se ocultos, embora o objeto ainda seja um Dog por baixo.

Downcasting vai na direção oposta, convertendo uma referência de pai de volta para um tipo filho. Isso requer um cast explícito porque nem sempre é seguro:

Animal animal = new Dog();  // Upcasting
Dog dog = (Dog) animal;     // Downcasting - conversão explícita necessária
dog.bark();                 // Agora podemos acessar os métodos de Dog

O downcasting é arriscado. Se o objeto não for realmente o tipo para o qual você está convertendo, o Java lança uma ClassCastException em tempo de execução:

Animal animal = new Cat();
Dog dog = (Dog) animal;  // Compila, mas ocorre um erro em tempo de execução!

O compilador não consegue capturar este erro porque ele apenas vê os tipos declarados. O tipo real do objeto só é conhecido quando o programa é executado. Na próxima lição, você aprenderá como verificar com segurança o tipo de um objeto antes de realizar o downcasting.

challenge icon

Desafio

Fácil

Vamos construir um sistema de player de mídia que demonstra tanto o upcasting quanto o downcasting em ação. Você criará uma hierarquia de tipos de mídia e praticará a conversão entre referências de pai e filho.

Você organizará seu código em quatro arquivos:

  • Media.java: Crie a classe base que todos os tipos de mídia compartilham. Cada item de mídia possui um campo title (String). Inclua um construtor para inicializá-lo, um método getter getTitle() e um método play() que imprime: "Playing: " + title
  • Song.java: Crie uma classe que estende Media. As músicas têm um campo adicional artist (String). Use super para a inicialização do pai. Sobrescreva play() para imprimir: "Playing song: " + title + " by " + artist. Adicione um método showArtist() que imprime: "Artist: " + artist
  • Podcast.java: Crie outra classe que estende Media. Os podcasts têm um campo episode (int). Sobrescreva play() para imprimir: "Playing podcast: " + title + " - Episode " + episode. Adicione um método showEpisode() que imprime: "Episode: " + episode
  • Main.java: Demonstre upcasting e downcasting com seus tipos de mídia. Você receberá quatro entradas: um título de música, um nome de artista, um título de podcast e um número de episódio.

    Primeiro, crie um Song e faça o upcast para uma referência Media. Chame play() nesta referência para ver o polimorfismo em tempo de execução funcionando.

    Em seguida, faça o downcast dessa referência Media de volta para um Song e chame showArtist() para acessar o método específico do filho.

    Depois, crie um Podcast e faça o upcast para uma referência Media. Chame play() nesta referência.

    Finalmente, faça o downcast dessa referência Media de volta para um Podcast e chame showEpisode().

Você receberá quatro entradas: o título da música (String), o nome do artista (String), o título do podcast (String) e o número do episódio (int).

Sua saída deve mostrar quatro linhas - duas para a música (sua saída de reprodução e informações do artista) e duas para o podcast (sua saída de reprodução e informações do episódio). Observe como o upcasting permite tratar diferentes tipos de mídia de forma uniforme, enquanto o downcasting permite acessar seus recursos exclusivos!

Folha de consulta

Em Java, o upcasting sobe na hierarquia de herança e acontece automaticamente. Um objeto filho pode ser atribuído a uma variável do tipo pai:

Dog dog = new Dog();
Animal animal = dog;  // Upcasting - automático

Quando você faz o upcasting, só pode acessar métodos definidos na classe pai, embora o objeto ainda seja do tipo filho por baixo.

O Downcasting converte uma referência de pai de volta para um tipo filho. Ele requer um cast explícito:

Animal animal = new Dog();  // Upcasting
Dog dog = (Dog) animal;     // Downcasting - cast explícito necessário
dog.bark();                 // Agora podemos acessar os métodos de Dog

O downcasting é arriscado. Se o objeto não for realmente do tipo para o qual você está convertendo, o Java lança uma ClassCastException em tempo de execução:

Animal animal = new Cat();
Dog dog = (Dog) animal;  // Compila, mas trava em tempo de execução!

O compilador não consegue capturar esse erro porque ele vê apenas os tipos declarados. O tipo real do objeto só é conhecido quando o programa é executado.

Experimente você mesmo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Ler entradas
        String songTitle = scanner.nextLine();
        String artistName = scanner.nextLine();
        String podcastTitle = scanner.nextLine();
        int episodeNumber = scanner.nextInt();
        
        // TODO: Criar uma Song e fazer o upcast para uma referência Media
        
        // TODO: Chamar play() na referência Media (demonstra polimorfismo)
        
        // TODO: Fazer o downcast da referência Media de volta para Song
        
        // TODO: Chamar showArtist() na referência Song
        
        // TODO: Criar um Podcast e fazer o upcast para uma referência Media
        
        // TODO: Chamar play() na referência Media
        
        // TODO: Fazer o downcast da referência Media de volta para Podcast
        
        // TODO: Chamar showEpisode() na referência Podcast
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos