- 1 1. O que você aprenderá neste artigo
- 2 2. O que o Polimorfismo Significa em Java
- 2.1 2.1 Tratando objetos através de um tipo pai
- 2.2 2.2 A mesma chamada de método, comportamento diferente
- 2.3 2.3 Por que usar um tipo pai é tão importante
- 2.4 2.4 Relação entre Polimorfismo e Sobrescrita de Métodos
- 2.5 2.5 Isto não é nova sintaxe — é um conceito de design
- 2.6 2.6 Principais Conclusões Desta Seção
- 3 3. O Mecanismo Central: Sobrescrita de Métodos e Ligação Dinâmica
- 3.1 3.1 O Que É Decidido em Tempo de Compilação vs Tempo de Execução
- 3.2 3.2 A Disponibilidade do Método É Verificada em Tempo de Compilação
- 3.3 3.3 O Método Real É Escolhido em Tempo de Execução
- 3.4 3.4 Por Que a Ligação Dinâmica Habilita o Polimorfismo
- 3.5 3.5 Por Que Métodos e Campos static São Diferentes
- 3.6 3.6 Confusão Comum de Iniciantes — Esclarecida
- 3.7 3.7 Resumo da Seção
- 4 4. Escrevendo Código Polimórfico Usando Herança (extends)
- 5 5. Escrevendo Código Polimórfico Usando Interfaces (implements)
- 5.1 5.1 Interfaces Representam “O Que um Objeto Pode Fazer”
- 5.2 5.2 Definindo Comportamento nas Classes Implementadoras
- 5.3 5.3 Usando o Tipo de Interface no Código de Chamada
- 5.4 5.4 Por Que as Interfaces São Preferidas na Prática
- 5.5 5.5 Exemplo do Mundo Real: Comportamento Trocável
- 5.6 5.6 Interface vs Classe Abstrata — Como Escolher
- 5.7 5.7 Resumo da Seção
- 6 6. Armadilhas Comuns: instanceof e Downcasting
- 7 7. Substituindo Declarações if / switch Por Polimorfismo
- 8 8. Diretrizes Práticas: Quando Usar Polimorfismo — e Quando Não Usar
- 9 9. Resumo: Principais Pontos sobre Polimorfismo em Java
- 10 10. FAQ: Perguntas Comuns Sobre Polimorfismo em Java
- 10.1 10.1 Qual é a diferença entre polimorfismo e sobrescrita de métodos?
- 10.2 10.2 A sobrecarga de métodos é considerada polimorfismo em Java?
- 10.3 10.3 Por que devo usar interfaces ou tipos pai?
- 10.4 10.4 Usar instanceof é sempre ruim?
- 10.5 10.5 Quando devo escolher uma classe abstrata em vez de uma interface?
- 10.6 10.6 O polimorfismo prejudica o desempenho?
- 10.7 10.7 Devo substituir todo if ou switch com polimorfismo?
- 10.8 10.8 Quais são bons exemplos de prática?
1. O que você aprenderá neste artigo
1.1 Polimorfismo em Java — Explicado em uma frase
Em Java, polimorfismo significa:
“Tratar diferentes objetos através do mesmo tipo, enquanto seu comportamento real muda dependendo do objeto concreto.”
Em termos mais simples, você pode escrever código usando uma classe ou interface pai, e depois trocar a implementação real sem mudar o código que a chama.
Essa ideia é um alicerce da programação orientada a objetos em Java.
1.2 Por que o Polimorfismo é Importante
Polimorfismo não é apenas um conceito teórico.
Ele ajuda diretamente a escrever código que é:
- Mais fácil de estender
- Mais fácil de manter
- Menos frágil quando os requisitos mudam
Situações típicas onde o polimorfismo se destaca incluem:
- Funcionalidades que ganharão mais variações ao longo do tempo
- Código repleto de crescentes instruções
if/switch - Lógica de negócio que muda independentemente de seus chamadores
No desenvolvimento Java do mundo real, o polimorfismo é uma das ferramentas mais eficazes para controlar a complexidade.
1.3 Por que iniciantes frequentemente têm dificuldade com o Polimorfismo
Muitos iniciantes acham o polimorfismo difícil no início, principalmente porque:
- O conceito é abstrato e não está ligado a uma nova sintaxe
- Frequentemente é explicado junto com herança e interfaces
- Ele foca em pensamento de design, não apenas na mecânica do código
Como resultado, os aprendizes podem “conhecer o termo”, mas sentir‑se inseguros sobre quando e por que usá‑lo.
1.4 O objetivo deste artigo
Ao final deste artigo, você entenderá:
- O que realmente significa polimorfismo em Java
- Como a sobrescrita de métodos e o comportamento em tempo de execução trabalham juntos
- Quando o polimorfismo melhora o design — e quando não melhora
- Como ele substitui lógica condicional em aplicações reais
O objetivo é ajudá‑lo a ver o polimorfismo não como um conceito difícil, mas como uma ferramenta de design natural e prática.
2. O que o Polimorfismo Significa em Java
2.1 Tratando objetos através de um tipo pai
No cerne do polimorfismo em Java há uma ideia simples:
Você pode tratar um objeto concreto através de sua classe ou interface pai.
Considere o exemplo a seguir:
Animal animal = new Dog();
Aqui está o que está acontecendo:
- O tipo da variável é
Animal - O objeto real é um
Dog
Mesmo que a variável seja declarada como Animal, o programa ainda funciona corretamente.
Isso não é um truque — é um recurso fundamental do sistema de tipos do Java.
2.2 A mesma chamada de método, comportamento diferente
Agora veja esta chamada de método:
animal.speak();
O código em si nunca muda.
Entretanto, o comportamento depende do objeto real armazenado em animal.
- Se
animalreferir a umDog→ a implementação do cachorro é executada - Se
animalreferir a umCat→ a implementação do gato é executada
É por isso que é chamado de polimorfismo —
uma interface, muitas formas de comportamento.
2.3 Por que usar um tipo pai é tão importante
Você pode se perguntar:
“Por que não usar
Dogem vez deAnimalem todos os lugares?”
Usar o tipo pai lhe dá vantagens poderosas:
- O código que chama não depende de classes concretas
- Novas implementações podem ser adicionadas sem modificar o código existente
- O código se torna mais fácil de reutilizar e testar
Por exemplo:
public void makeAnimalSpeak(Animal animal) {
animal.speak();
}
Este método funciona para:
DogCat- Qualquer classe de animal futura
O chamador só se importa com o que o objeto pode fazer, não com o que ele é.
2.4 Relação entre Polimorfismo e Sobrescrita de Métodos
Polimorfismo costuma ser confundido com sobrescrita de métodos, então vamos esclarecer.
- Sobrescrita de método → Uma subclasse fornece sua própria implementação de um método da classe pai
- Polimorfismo → Chamar o método sobrescrito através de uma referência de tipo pai
A sobrescrita possibilita o polimorfismo, mas o polimorfismo é o princípio de design que o utiliza.
2.5 Isto não é nova sintaxe — é um conceito de design
Polimorfismo não introduz novas palavras-chave Java ou sintaxe especial.
- Você já usa
class,extendseimplements - Você já chama métodos da mesma maneira
O que muda é como você pensa sobre a interação de objetos.
Em vez de escrever código que depende de classes concretas,
você projeta código que depende de abstrações.
2.6 Principais Conclusões Desta Seção
Para resumir:
- O polimorfismo permite que objetos sejam usados através de um tipo comum
- O comportamento real é determinado em tempo de execução
- O chamador não precisa saber detalhes de implementação
Na próxima seção, exploraremos por que o Java pode fazer isso,
olhando para sobrescrita de métodos e ligação dinâmica em detalhes.
3. O Mecanismo Central: Sobrescrita de Métodos e Ligação Dinâmica
3.1 O Que É Decidido em Tempo de Compilação vs Tempo de Execução
Para entender verdadeiramente o polimorfismo no Java, você deve separar o comportamento em tempo de compilação do comportamento em tempo de execução.
O Java toma duas decisões diferentes em duas etapas diferentes:
- Tempo de compilação → Verifica se uma chamada de método é válida para o tipo da variável
- Tempo de execução → Decide qual implementação do método é realmente executada
Essa separação é a base do polimorfismo.
3.2 A Disponibilidade do Método É Verificada em Tempo de Compilação
Considere este código novamente:
Animal animal = new Dog();
animal.speak();
Em tempo de compilação, o compilador Java olha apenas para:
- O tipo declarado :
Animal
Se Animal define um método speak(), a chamada é considerada válida.
O compilador não se importa com qual objeto concreto será atribuído depois.
Isso significa:
- Você só pode chamar métodos que existem no tipo pai
- O compilador não “adivinha” o comportamento da subclasse
3.3 O Método Real É Escolhido em Tempo de Execução
Quando o programa é executado, o Java avalia:
- A qual objeto
animalrealmente se refere - Se essa classe sobrescreve o método chamado
Se Dog sobrescreve speak(), então a implementação do Dog é executada, não a do Animal.
Essa seleção de método em tempo de execução é chamada de ligação dinâmica (ou despacho dinâmico).
3.4 Por Que a Ligação Dinâmica Habilita o Polimorfismo
Sem ligação dinâmica, o polimorfismo não existiria.
Se o Java sempre chamasse métodos com base no tipo declarado da variável,
este código seria sem sentido:
Animal animal = new Dog();
A ligação dinâmica permite que o Java:
- Adie a decisão do método até o tempo de execução
- Combine o comportamento com o objeto real
Em resumo:
- Sobrescrita define a variação
- Ligação dinâmica a ativa
Juntas, elas tornam o polimorfismo possível.
3.5 Por Que Métodos e Campos static São Diferentes
Uma fonte comum de confusão são os membros static.
Regra importante:
- Métodos e campos estáticos NÃO participam do polimorfismo
Por quê?
- Eles pertencem à classe , não ao objeto
- Eles são resolvidos em tempo de compilação , não em tempo de execução
Isso significa:
Animal animal = new Dog();
animal.staticMethod(); // resolved using Animal, not Dog
A seleção do método é fixa e não muda com base no objeto real.
3.6 Confusão Comum de Iniciantes — Esclarecida
Vamos resumir as regras principais de forma clara:
- Posso chamar este método? → Verificado usando o tipo declarado (tempo de compilação)
- Qual implementação executa? → Decidido pelo objeto real (tempo de execução)
- O que suporta o polimorfismo? → Apenas métodos de instância sobrescritos
Uma vez que essa distinção esteja clara, o polimorfismo para de parecer misterioso.
3.7 Resumo da Seção
- O Java valida chamadas de métodos usando o tipo da variável
- O tempo de execução escolhe o método sobrescrito com base no objeto
- Esse mecanismo é chamado de ligação dinâmica
- Membros estáticos não são polimórficos
Na próxima seção, veremos como escrever código polimórfico usando herança (extends), com exemplos concretos.
4. Escrevendo Código Polimórfico Usando Herança (extends)
4.1 O Padrão Básico de Herança
Vamos começar com a maneira mais direta de implementar polimorfismo em Java: herança de classes.
class Animal {
public void speak() {
System.out.println("Some sound");
}
}
class Dog extends Animal {
@Override
public void speak() {
System.out.println("Woof");
}
}
class Cat extends Animal {
@Override
public void speak() {
System.out.println("Meow");
}
}
Aqui:
Animaldefine um comportamento comum- Cada subclasse sobrescreve esse comportamento com sua própria implementação
Essa estrutura é a base do polimorfismo via herança.
4.2 Usar o Tipo Pai é a Chave
Agora veja o código de chamada:
Animal a1 = new Dog();
Animal a2 = new Cat();
a1.speak();
a2.speak();
Embora ambas as variáveis sejam do tipo Animal,
Java executa a implementação correta com base no objeto real.
Dog→"Woof"Cat→"Meow"
O código de chamada não precisa saber — ou se importar — com a classe concreta.
4.3 Por que Não Usar o Tipo da Subclasse Diretamente?
Iniciantes frequentemente escrevem código assim:
Dog dog = new Dog();
dog.speak();
Isso funciona, mas limita a flexibilidade.
Se você introduzir outro tipo de animal mais tarde, deverá:
- Alterar declarações de variáveis
- Atualizar parâmetros de métodos
- Modificar coleções
Usar o tipo pai evita essas mudanças:
List<Animal> animals = List.of(new Dog(), new Cat());
A estrutura permanece a mesma mesmo quando novas subclasses são adicionadas.
4.4 O Que Pertence à Classe Pai?
Ao projetar polimorfismo baseado em herança, a classe pai deve conter:
- Comportamento compartilhado por todas as subclasses
- Métodos que fazem sentido independentemente do tipo concreto
Evite colocar comportamento na classe pai que se aplica apenas a algumas subclasses.
Isso geralmente indica um problema de design.
Uma boa regra prática:
Se tratar um objeto como o tipo pai parece “errado”, a abstração está incorreta.
4.5 Usando Classes Abstratas
Às vezes a classe pai não deve ter nenhuma implementação padrão.
Nesses casos, use uma classe abstrata.
abstract class Animal {
public abstract void speak();
}
Isso impõe regras:
- Subclasses devem implementar
speak() - A classe pai não pode ser instanciada
Classes abstratas são úteis quando você quer forçar um contrato, não fornecer comportamento.
4.6 As Desvantagens da Herança
Herança é poderosa, mas tem compromissos:
- Acoplamento forte entre pai e filho
- Hierarquias de classes rígidas
- Refatoração posterior mais difícil
Por essas razões, muitos designs modernos em Java favorecem interfaces em vez de herança.
4.7 Resumo da Seção
- Herança permite polimorfismo via sobrescrita de métodos
- Sempre interaja através do tipo pai
- Classes abstratas impõem o comportamento requerido
- Herança deve ser usada com cautela
Em seguida, exploraremos polimorfismo usando interfaces, que costuma ser a abordagem preferida em projetos Java do mundo real.
5. Escrevendo Código Polimórfico Usando Interfaces (implements)
5.1 Interfaces Representam “O Que um Objeto Pode Fazer”
No desenvolvimento Java do mundo real, interfaces são a forma mais comum de implementar polimorfismo.
Uma interface representa uma capacidade ou papel, não uma identidade.
interface Speaker {
void speak();
}
Neste estágio, não há implementação — apenas um contrato.
Qualquer classe que implemente esta interface promete fornecer esse comportamento.
5.2 Definindo Comportamento nas Classes Implementadoras
Agora vamos implementar a interface:
class Dog implements Speaker {
@Override
public void speak() {
System.out.println("Woof");
}
}
class Cat implements Speaker {
@Override
public void speak() {
System.out.println("Meow");
}
}
Essas classes não compartilham uma relação pai‑filho.
No entanto, podem ser tratadas uniformemente através da interface Speaker.
5.3 Usando o Tipo de Interface no Código de Chamada
O poder das interfaces fica claro no lado do chamador:
Speaker s1 = new Dog();
Speaker s2 = new Cat();
s1.speak();
s2.speak();
O código de chamada:
- Depende apenas da interface
- Não tem conhecimento de implementações concretas
- Funciona inalterado quando novas implementações são adicionadas
Isso é polimorfismo verdadeiro na prática.
5.4 Por Que as Interfaces São Preferidas na Prática
As interfaces são frequentemente favorecidas em vez da herança porque elas fornecem:
- Acoplamento frouxo
- Flexibilidade entre classes não relacionadas
- Suporte para múltiplas implementações
Uma classe pode implementar múltiplas interfaces, mas só pode estender uma classe.
Isso torna as interfaces ideais para projetar sistemas extensíveis.
5.5 Exemplo do Mundo Real: Comportamento Trocável
As interfaces brilham em cenários onde o comportamento pode mudar ou expandir:
- Métodos de pagamento
- Canais de notificação
- Estratégias de armazenamento de dados
- Mecanismos de log
Exemplo:
public void notifyUser(Notifier notifier) {
notifier.send();
}
Você pode adicionar novos métodos de notificação sem modificar este método.

5.6 Interface vs Classe Abstrata — Como Escolher
Se você não tiver certeza de qual usar, siga esta diretriz:
- Use uma interface quando você se importar com o comportamento
- Use uma classe abstrata quando quiser estado compartilhado ou implementação
Na maioria dos designs Java modernos, começar com uma interface é a escolha mais segura.
5.7 Resumo da Seção
- Interfaces definem contratos de comportamento
- Elas habilitam polimorfismo flexível e com acoplamento frouxo
- O código de chamada depende de abstrações, não de implementações
- Interfaces são a escolha padrão no design profissional de Java
Em seguida, examinaremos uma armadilha comum: usar instanceof e downcasting, e por que eles frequentemente indicam um problema de design.
6. Armadilhas Comuns: instanceof e Downcasting
6.1 Por Que os Desenvolvedores Recorrem ao instanceof
Ao aprender polimorfismo, muitos desenvolvedores eventualmente escrevem código como este:
if (speaker instanceof Dog) {
Dog dog = (Dog) speaker;
dog.fetch();
}
Isso geralmente acontece porque:
- Uma subclasse tem um método não declarado na interface
- O comportamento precisa diferir com base na classe concreta
- Requisitos foram adicionados após o design original
Querer “verificar o tipo real” é um instinto natural — mas isso frequentemente sinaliza um problema mais profundo.
6.2 O Que Dá Errado Quando o instanceof se Espalha
Usar instanceof ocasionalmente não é inerentemente errado.
O problema surge quando ele se torna o mecanismo principal de controle.
if (speaker instanceof Dog) {
...
} else if (speaker instanceof Cat) {
...
} else if (speaker instanceof Bird) {
...
}
Esse padrão leva a:
- Código que deve mudar toda vez que uma nova classe é adicionada
- Lógica centralizada no chamador em vez do objeto
- Perda do benefício principal do polimorfismo
Nesse ponto, o polimorfismo é efetivamente contornado.
6.3 O Risco do Downcasting
O downcasting converte um tipo pai em um subtipo específico:
Animal animal = new Dog();
Dog dog = (Dog) animal;
Isso funciona apenas se a suposição estiver correta.
Se o objeto não for realmente um Dog, o código falha em tempo de execução com uma ClassCastException.
Downcasting:
- Empurra erros do tempo de compilação para o tempo de execução
- Faz suposições sobre a identidade do objeto
- Aumenta a fragilidade
6.4 Isso Pode Ser Resolvido com Polimorfismo?
Antes de usar instanceof, pergunte a si mesmo:
- Esse comportamento pode ser expresso como um método?
- A interface pode ser expandida em vez disso?
- A responsabilidade pode ser movida para dentro da própria classe?
Por exemplo, em vez de verificar tipos:
speaker.performAction();
Deixe cada classe decidir como realizar essa ação.
6.5 Quando o instanceof É Aceitável
Há casos em que o instanceof é razoável:
- Integração com bibliotecas externas
- Código legado que você não pode redesenhar
- Camadas de limite (adaptadores, serializadores)
A regra principal:
Mantenha
instanceofnas bordas, não na lógica central.
6.6 Diretriz Prática
- Evite
instanceofna lógica de negócios - Evite designs que exigem downcasting frequente
- Se sentir que é forçado a usá‑los, reconsidere a abstração
Em seguida, veremos como o polimorfismo pode substituir lógica condicional (if / switch) de forma limpa e escalável.
7. Substituindo Declarações if / switch Por Polimorfismo
7.1 Um Cheiro de Código Condicional Comum
Considere este exemplo típico:
public void processPayment(String type) {
if ("credit".equals(type)) {
// Credit card payment
} else if ("bank".equals(type)) {
// Bank transfer
} else if ("paypal".equals(type)) {
// PayPal payment
}
}
À primeira vista, este código parece correto.
No entanto, à medida que o número de tipos de pagamento cresce, a complexidade também aumenta.
7.2 Aplicando Polimorfismo Em Seu Lugar
Podemos refatorar isso usando polimorfismo.
interface Payment {
void pay();
}
class CreditPayment implements Payment {
@Override
public void pay() {
// Credit card payment
}
}
class BankPayment implements Payment {
@Override
public void pay() {
// Bank transfer
}
}
Código de chamada:
public void processPayment(Payment payment) {
payment.pay();
}
Agora, adicionar um novo tipo de pagamento não requer nenhuma alteração neste método.
7.3 Por Que Esta Abordagem É Melhor
Este design oferece vários benefícios:
- A lógica condicional desaparece
- Cada classe possui seu próprio comportamento
- Novas implementações podem ser adicionadas com segurança
O sistema torna‑se aberto para extensão, fechado para modificação.
7.4 Quando Não Substituir Condicionais
Polimorfismo nem sempre é a escolha certa.
Evite usá‑lo em excesso quando:
- O número de casos é pequeno e fixo
- As diferenças de comportamento são triviais
- Classes adicionais reduzem a clareza
Condicionais simples costumam ser mais claros para lógica simples.
7.5 Como Decidir na Prática
Pergunte a si mesmo:
- Este ramo crescerá ao longo do tempo?
- Novos casos serão adicionados por outras pessoas?
- As mudanças afetam muitos lugares?
Se a resposta for “sim”, o polimorfismo provavelmente é a melhor escolha.
7.6 Refatoração Incremental É a Melhor
Você não precisa de um design perfeito desde o início.
- Comece com condicionais
- Refatore quando a complexidade aumentar
- Deixe o código evoluir naturalmente
Esta abordagem mantém o desenvolvimento prático e sustentável.
Em seguida, discutiremos quando o polimorfismo deve ser usado — e quando não deve — em projetos reais.
8. Diretrizes Práticas: Quando Usar Polimorfismo — e Quando Não Usar
8.1 Sinais de que o Polimorfismo É Adequado
O polimorfismo é mais valioso quando mudanças são esperadas.
Você deve considerá‑lo fortemente quando:
- O número de variações provavelmente aumentará
- O comportamento muda independentemente do chamador
- Você quer manter o código de chamada estável
- Diferentes implementações compartilham o mesmo papel
Nesses casos, o polimorfismo ajuda a localizar mudanças e reduzir efeitos cascata.
8.2 Sinais de que o Polimorfismo É Exagero
Polimorfismo não é gratuito. Ele introduz mais tipos e indireção.
Evite‑lo quando:
- O número de casos é fixo e pequeno
- A lógica é curta e improvável de mudar
- Classes extras prejudicariam a legibilidade
Forçar o polimorfismo “por precaução” costuma gerar complexidade desnecessária.
8.3 Evite Projetar para um Futuro Imaginário
Um erro comum de iniciantes é adicionar polimorfismo de forma preventiva:
“Podemos precisar disso mais tarde.”
Na prática:
- Requisitos frequentemente mudam de maneiras inesperadas
- Muitas extensões previstas nunca acontecem
Geralmente é melhor começar simples e refatorar quando necessidades reais surgirem.
8.4 Uma Visão Prática do Princípio da Substituição de Liskov (LSP)
Você pode encontrar o Princípio da Substituição de Liskov (LSP) ao estudar POO.
Uma maneira prática de entendê‑lo é:
“Se eu substituir um objeto por um de seus subtipos, nada deve quebrar.”
Se usar um subtipo causar surpresas, exceções ou tratamento especial,
a abstração provavelmente está errada.
8.5 Pergunte a Pergunta de Design Certa
Quando incerto, pergunte:
- O chamador precisa saber qual implementação é esta?
- Ou apenas qual comportamento ela fornece?
Se apenas o comportamento for suficiente, o polimorfismo geralmente é a escolha certa.
8.6 Resumo da Seção
- O polimorfismo é uma ferramenta para gerenciar mudanças
- Use-o onde variação é esperada
- Evite abstração prematura
- Refatore em direção ao polimorfismo quando necessário
A seguir, concluiremos o artigo com um resumo claro e uma seção de FAQ.
9. Resumo: Principais Pontos sobre Polimorfismo em Java
9.1 A Ideia Central
No cerne, o polimorfismo em Java trata de um princípio simples:
O código deve depender de abstrações, não de implementações concretas.
Ao interagir com objetos através de classes pai ou interfaces,
você permite que o comportamento mude sem reescrever o código chamador.
9.2 O Que Você Deve Lembrar
Aqui estão os pontos mais importantes deste artigo:
- O polimorfismo é um conceito de design, não uma nova sintaxe
- É implementado através de sobrescrita de métodos e ligação dinâmica
- Tipos pai definem o que pode ser chamado
- O comportamento real é decidido em tempo de execução
- Interfaces são frequentemente a abordagem preferida
instanceofe downcasting devem ser usados com parcimônia- O polimorfismo ajuda a substituir lógica condicional crescente
9.3 Um Caminho de Aprendizado para Iniciantes
Se você ainda está construindo intuição, siga esta progressão:
- Fique confortável usando tipos de interface
- Observe como métodos sobrescritos se comportam em tempo de execução
- Entenda por que condicionais se tornam mais difíceis de manter
- Refatore em direção ao polimorfismo quando a complexidade cresce
Com a prática, o polimorfismo se torna uma escolha de design natural em vez de um “conceito difícil.”
10. FAQ: Perguntas Comuns Sobre Polimorfismo em Java
10.1 Qual é a diferença entre polimorfismo e sobrescrita de métodos?
A sobrescrita de métodos é um mecanismo — redefinindo um método em uma subclasse.
O polimorfismo é o princípio que permite que métodos sobrescritos sejam chamados através de uma referência de tipo pai.
10.2 A sobrecarga de métodos é considerada polimorfismo em Java?
Na maioria dos contextos Java, não.
A sobrecarga é resolvida em tempo de compilação, enquanto o polimorfismo depende do comportamento em tempo de execução.
10.3 Por que devo usar interfaces ou tipos pai?
Porque eles:
- Reduzem o acoplamento
- Melhoram a extensibilidade
- Estabilizam o código chamador
Seu código se torna mais fácil de manter à medida que os requisitos evoluem.
10.4 Usar instanceof é sempre ruim?
Não, mas deve ser limitado.
É aceitável em:
- Camadas de fronteira
- Sistemas legados
- Pontos de integração
Evite usá-lo na lógica de negócios principal.
10.5 Quando devo escolher uma classe abstrata em vez de uma interface?
Use uma classe abstrata quando:
- Você precisa de estado compartilhado ou implementação
- Há uma forte relação “é-um”
Use interfaces quando o comportamento e a flexibilidade importam mais.
10.6 O polimorfismo prejudica o desempenho?
Em aplicações de negócios típicas, as diferenças de desempenho são negligenciáveis.
Legibilidade, manutenibilidade e correção são muito mais importantes.
10.7 Devo substituir todo if ou switch com polimorfismo?
Não.
Use polimorfismo quando variação é esperada e crescente.
Mantenha condicionais quando a lógica é simples e estável.
10.8 Quais são bons exemplos de prática?
Ótimos cenários de prática incluem:
- Processamento de pagamentos
- Sistemas de notificação
- Exportadores de formato de arquivo
- Estratégias de logging
Onde quer que o comportamento precise ser trocável, o polimorfismo se encaixa naturalmente

