Prof. José Rodolfo Beluzo
Polimorfismo é a capacidade de um mesmo método comportar-se de maneiras diferentes dependendo do objeto que o executa.
Animal a = new Cachorro();
a.fazerSom(); // "Au au!"
Animal b = new Gato();
b.fazerSom(); // "Miau!"
A variável é do tipo Animal, mas o comportamento depende do objeto real.
Uma classe filha redefine um método da classe pai.
class Animal {
public void fazerSom() { System.out.println("Som genérico..."); }
}
class Cachorro extends Animal {
@Override
public void fazerSom() {. System.out.println("Au au!"); }
}
class Gato extends Animal {
@Override
public void fazerSom() { System.out.println("Miau!"); }
}
Animal a1 = new Cachorro();
Animal a2 = new Gato();
a1.fazerSom(); // Au au!
a2.fazerSom(); // Miau!
Uma mesma referência (Animal), vários comportamentos.
// Classe base
abstract class Frete {
public abstract double calcular(double peso,
double distancia);
}
// Implementações
class Sedex extends Frete {
public double calcular(double peso, double distancia) {
return peso * 1.2 + distancia * 0.5;
}
}
class Loggi extends Frete {
public double calcular(double peso, double distancia) {
return peso * 0.9 + distancia * 0.7;
}
}
class Motoboy extends Frete {
public double calcular(double peso, double distancia) {
return 15.0; // tarifa fixa
}
}
//Classe principal
public class App {
public static void main(String[] args) throws Exception {
Frete s = new Sedex();
Frete l = new Loggi();
Venda v1 = new Venda(3,s);
Venda v2 = new Venda(3,l);
v1.calcularVenda(0.5,50);
v2.calcularVenda(0.5,50);
v1.exibeValorFinal();
v2.exibeValorFinal();
}
}
Explicação: Cada classe calcula o frete de forma diferente, mas todas podem ser usadas pelo mesmo método. Se surgir nova transportadora, basta criar outra classe, sem alterar o código da Loja.
Imagine um sistema de e-commerce que aceita diferentes formas de pagamento. O método processar() deve funcionar para qualquer tipo de pagamento, sem alterar o código principal do sistema.
Tarefa:
Pagamento com o método abstrato processar(double valor).PagamentoCartao – exiba mensagem de processamento no cartão e aplica 5% de taxa no valor.PagamentoPix – exiba mensagem de processamento do PIX com 5% de desconto do valor.PagamentoBoleto – exiba mensagem de pagamento no valor original.Caixa com um método pagar() que receba um objeto do tipo Pagamento e chame processar().main, teste chamadas com diferentes formas de pagamento.
// exemplo de execução esperada:
Caixa caixa = new Caixa();
caixa.pagar(new PagamentoCartao(), 250); //Pagamento no Cartão: Valor final - R$262.50
caixa.pagar(new PagamentoPix(), 250); // Pagamento no Pix: Valor Final - R$237.50
caixa.pagar(new PagamentoBoleto(), 250); // Pagamento no Boleto: Valor Final - R$250.00
default e static methods.interface Conduzivel { void mover(); }
interface Abastecivel { void abastecer(double litros); }
class Carro implements Conduzivel, Abastecivel {
@Override public void mover(){ System.out.println("Acelerando..."); }
@Override public void abastecer(double l){ /* ... */ }
}
Quando diferentes classes implementam a mesma interface, e podem ser tratadas por ela.
interface Forma {
double area();
}
class Quadrado implements Forma {
public double area() {
return 25;
}
}
class Circulo implements Forma {
public double area() {
return 12.56;
}
}
Forma f = new Quadrado();
System.out.println(f.area()); // 25
f = new Circulo();
System.out.println(f.area()); // 12.56
Mesma chamada (area()), implementações diferentes.
Uma classe pode implementar mais de uma interface. Dependendo de qual interface é usada, o objeto assume comportamentos diferentes.
// Interface de envio
interface Notificador {
void enviar(String msg);
}
// Interface de registro
interface Registravel {
void registrarLog(String msg);
}
// Implementações
class Email implements Notificador {
public void enviar(String msg) {
System.out.println("E-mail: " + msg);
}
}
class PushNotification implements Notificador, Registravel {
public void enviar(String msg) {
System.out.println("Push: " + msg);
}
public void registrarLog(String msg) {
System.out.println("Log Push: " + msg);
}
}
class SMS implements Notificador, Registravel {
public void enviar(String msg) {
System.out.println("SMS: " + msg);
}
public void registrarLog(String msg) {
System.out.println("Log SMS: " + msg);
}
}
// Uso polimórfico
public class Sistema {
public static void main(String[] args) {
List n = List.of(
new Email(),
new PushNotification(),
new SMS()
);
for (Notificador x : n) {
x.enviar("Promoção!");
}
List r = List.of(
new PushNotification(),
new SMS()
);
for (Registravel x : r) {
x.registrarLog("OK");
}
}
}
Explicação: O mesmo objeto pode ser usado como Notificador ou Registravel. O sistema não sabe qual classe concreta está sendo usada — ele apenas chama os métodos das interfaces.
Polimorfismo é a capacidade de chamar o mesmo método e obter resultados diferentes, dependendo do objeto que o executa.
Acontece principalmente por:
Você foi contratado para modelar parte de um sistema de automação residencial em Java. Nesse sistema, diferentes dispositivos podem possuir capacidades distintas, como ligar/desligar, se conectar à internet e enviar relatórios de status.
Implemente o sistema seguindo os requisitos a seguir:
Ligavel
void ligar();void desligar();boolean isLigado();Conectavel
void conectar(String rede);void desconectar();boolean isConectado();Monitoravel
String gerarRelatorioStatus();Dispositivo com:
String nome; e String local;nome e local.String getIdentificacao() que retorne algo no formato:"nome (local)".
LampadaInteligente
Dispositivo e implementar Ligavel e Monitoravel.gerarRelatorioStatus), retorne algo como:"Lâmpada X (Sala): ligada" ou "Lâmpada X (Sala): desligada".
CameraSeguranca
Dispositivo e implementar Ligavel, Conectavel e Monitoravel.AppCasaInteligente
// Programa principal
import java.util.ArrayList;
import java.util.List;
public class AppCasaInteligente {
public static void main(String[] args) {
// Lista de dispositivos que podem ser monitorados
List dispositivos = new ArrayList<>();
// Criação dos dispositivos
LampadaInteligente lampadaSala = new LampadaInteligente("Lâmpada Sala", "Sala");
CameraSeguranca cameraGaragem = new CameraSeguranca("Câmera Garagem", "Garagem");
dispositivos.add(lampadaSala);
dispositivos.add(cameraGaragem);
System.out.println("=== Ligando dispositivos ligáveis ===");
for (Monitoravel m : dispositivos) {
if (m instanceof Ligavel) {
Ligavel l = (Ligavel) m;
l.ligar();
}
}
System.out.println("\n=== Conectando dispositivos conectáveis ===");
for (Monitoravel m : dispositivos) {
if (m instanceof Conectavel) {
Conectavel c = (Conectavel) m;
c.conectar("WiFi-Casa");
}
}
System.out.println("\n=== Relatórios de Status ===");
for (Monitoravel m : dispositivos) {
System.out.println(m.gerarRelatorioStatus());
}
}
}
=== Ligando dispositivos ligáveis ===
Lâmpada Sala (Sala) foi ligada.
Câmera Câmera Garagem (Garagem) foi ligada.
=== Conectando dispositivos conectáveis ===
Câmera Câmera Garagem (Garagem) conectada à rede WiFi-Casa.
=== Relatórios de Status ===
Lâmpada Lâmpada Sala (Sala): ligada
Câmera Câmera Garagem (Garagem): ligada, conectada à rede WiFi-Casa