Desafio Java
Processador de arquivos polimórfico com casting seguro
Enunciado
Crie uma hierarquia para processar diferentes tipos de arquivos: Arquivo (abstrata) com método processar(). As subclasses Texto, Imagem e Video devem implementar processar() com mensagens específicas. Texto tem extrairPalavras(), Imagem tem redimensionar(), Video tem reproduzir(). No main, crie uma lista de Arquivo com instâncias variadas. Percorra a lista, chame processar() e, usando instanceof com pattern, chame o método específico de cada tipo. Além disso, demonstre um casting explícito seguro e um casting que lançaria ClassCastException (capture a exceção e imprima uma mensagem).
Requisitos
Arquivoé abstrata com método abstratoprocessar().- Cada subclasse implementa
processar()e tem um método específico. - No
main, percorra a lista e useinstanceofcom pattern para chamar os métodos específicos. - Demonstre um casting explícito seguro (após verificação) e um casting inseguro que lança
ClassCastException, capturada comtry-catch.
Código inicial
import java.util.List;
import java.util.ArrayList;
abstract class Arquivo {
abstract void processar();
}
// TODO: crie Texto, Imagem e Video
public class Main {
public static void main(String[] args) {
List<Arquivo> arquivos = new ArrayList<>();
// TODO: adicione instâncias
// TODO: percorra, processe e chame métodos específicos
// TODO: demonstre casting seguro e inseguro
}
}
Saída esperada
Processando arquivo de texto.
Extraindo palavras...
Processando imagem.
Redimensionando imagem...
Processando vídeo.
Reproduzindo vídeo...
Casting seguro: Texto
Casting inseguro capturado: class Imagem cannot be cast to class Texto (Imagem and Texto are in unnamed module of loader 'app')
Ver dica
Para o casting inseguro, pegue um objeto Imagem e tente convertê-lo para Texto. Capture ClassCastException e imprima a mensagem da exceção.
Mostrar solução
import java.util.List;
import java.util.ArrayList;
abstract class Arquivo {
abstract void processar();
}
class Texto extends Arquivo {
@Override
void processar() {
System.out.println("Processando arquivo de texto.");
}
void extrairPalavras() {
System.out.println("Extraindo palavras...");
}
}
class Imagem extends Arquivo {
@Override
void processar() {
System.out.println("Processando imagem.");
}
void redimensionar() {
System.out.println("Redimensionando imagem...");
}
}
class Video extends Arquivo {
@Override
void processar() {
System.out.println("Processando vídeo.");
}
void reproduzir() {
System.out.println("Reproduzindo vídeo...");
}
}
public class Main {
public static void main(String[] args) {
List<Arquivo> arquivos = new ArrayList<>();
arquivos.add(new Texto());
arquivos.add(new Imagem());
arquivos.add(new Video());
for (Arquivo a : arquivos) {
a.processar(); // despacho dinâmico
// instanceof com pattern
if (a instanceof Texto t) {
t.extrairPalavras();
} else if (a instanceof Imagem i) {
i.redimensionar();
} else if (a instanceof Video v) {
v.reproduzir();
}
}
// Casting seguro: após verificação
Arquivo arquivoTexto = new Texto();
if (arquivoTexto instanceof Texto) {
Texto t = (Texto) arquivoTexto;
System.out.println("Casting seguro: " + t.getClass().getSimpleName());
}
// Casting inseguro: tentar converter Imagem para Texto
Arquivo arquivoImagem = new Imagem();
try {
Texto t = (Texto) arquivoImagem; // lança ClassCastException
} catch (ClassCastException e) {
System.out.println("Casting inseguro capturado: " + e.getMessage());
}
}
}
Passo a passo
- Definimos
Arquivocomo classe abstrata comprocessar(). As subclassesTexto,ImagemeVideoimplementamprocessar()com mensagens distintas. - Cada subclasse adiciona um método específico:
extrairPalavras(),redimensionar()ereproduzir(). - No
main, criamos uma lista deArquivoe adicionamos uma instância de cada subclasse. - No loop, chamamos
a.processar(). O despacho dinâmico seleciona a implementação correta de acordo com o tipo real do objeto. - Em seguida, usamos
instanceofcom pattern para identificar o tipo e chamar o método específico. A variável declarada (ex.:t) já está convertida, evitando cast explícito. - Para demonstrar casting seguro, criamos um
Arquivoque é umTexto, verificamos cominstanceofe então fazemos(Texto) arquivoTexto. Isso é seguro porque a verificação garante o tipo. - Para o casting inseguro, criamos um
Arquivoque é umaImageme tentamos convertê-lo paraTexto. Isso lançaClassCastException, que capturamos e imprimimos a mensagem. - A mensagem da exceção varia um pouco entre versões da JVM, mas o formato é padronizado.
Por que funciona
O polimorfismo permite tratar todos os arquivos uniformemente através da superclasse. O despacho dinâmico executa o método correto. O instanceof com pattern simplifica a verificação e o acesso a métodos específicos. O casting explícito é necessário quando queremos tratar um objeto como um tipo mais específico, mas só é seguro se o objeto realmente for daquele tipo. Caso contrário, a JVM lança ClassCastException, que pode ser tratada.
Erros comuns
- Fazer cast sem verificar:
Texto t = (Texto) new Imagem();lançaClassCastExceptionem tempo de execução. Sempre verifique cominstanceofantes. - Confundir
instanceofcomgetClass():instanceofconsidera subclasses, enquantogetClass() ==exige tipo exato. Useinstanceofpara polimorfismo. - Esquecer de capturar a exceção: se não capturar, o programa termina abruptamente. Use
try-catchpara tratar. - Ordem errada de
instanceof: se uma subclasse estender outra, verifique a mais específica primeiro. Aqui, como são irmãs, não há problema.
Outra forma de resolver
Poderia-se usar o padrão Visitor para evitar instanceof, mas isso adiciona complexidade. Para hierarquias pequenas, instanceof com pattern é aceitável e mais direto.
Saída esperada
Processando arquivo de texto.
Extraindo palavras...
Processando imagem.
Redimensionando imagem...
Processando vídeo.
Reproduzindo vídeo...
Casting seguro: Texto
Casting inseguro capturado: class Imagem cannot be cast to class Texto (Imagem and Texto are in unnamed module of loader 'app')