Polimorfismo e Abstração

Polimorfismo é uma característica central da OOP que torna o código mais flexível e extensível.

O que é Polimorfismo

Polimorfismo significa que o mesmo método se comporta de maneira diferente em objetos diferentes.

Benefícios do Polimorfismo

Benefício Descrição
Flexibilidade Mesma interface, diferentes implementações
Extensibilidade Adicionar novas subclasses não requer modificar o código pai
Código simplificado Usar referências da classe pai para operar em objetos filhos

Upcasting

Um objeto filho pode ser atribuído a uma referência da classe pai.

JAVA
Animal animal = new Dog();  // Upcasting

Exemplo: Upcasting

JAVA
public class Animal {
    public void eat() {
        System.out.println("Animal está comendo");
    }
}

public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("Cão está roendo um osso");
    }
    
    public void bark() {
        System.out.println("Latindo");
    }
}

public class PolymorphismDemo {
    public static void main(String[] args) {
        Animal animal = new Dog();  // Upcasting
        animal.eat();  // Cão está roendo um osso (chama o eat do Dog)
        // animal.bark();  // Erro de compilação! Referência pai só pode acessar métodos pai
    }
}
▶ Experimente

Vinculação Dinâmica

Em tempo de execução, o método é chamado com base no tipo real do objeto, não no tipo em tempo de compilação.

Exemplo: Vinculação Dinâmica

JAVA
public class Animal {
    public void speak() {
        System.out.println("Animal faz um som");
    }
}

public class Dog extends Animal {
    @Override
    public void speak() {
        System.out.println("Au au");
    }
}

public class Cat extends Animal {
    @Override
    public void speak() {
        System.out.println("Miau miau");
    }
}

public class DynamicBinding {
    public static void makeSound(Animal animal) {
        animal.speak();  // Decidido em tempo de execução qual speak chamar
    }
    
    public static void main(String[] args) {
        makeSound(new Dog());  // Au au
        makeSound(new Cat());  // Miau miau
    }
}
▶ Experimente

Classes Abstratas

Classes abstratas não podem ser instanciadas—só podem ser herdadas.

Métodos Abstratos

Métodos sem corpo que as subclasses devem implementar.

JAVA
public abstract class Shape {
    // Método abstrato: sem corpo
    public abstract double area();
    
    // Método regular: tem corpo
    public void display() {
        System.out.println("Área: " + area());
    }
}

Exemplo: Classe Abstrata

JAVA
public abstract class Shape {
    protected String name;
    
    public Shape(String name) {
        this.name = name;
    }
    
    // Métodos abstratos
    public abstract double area();
    public abstract double perimeter();
    
    public void display() {
        System.out.println(name + " - Área: " + area() + ", Perímetro: " + perimeter());
    }
}

public class Circle extends Shape {
    private double radius;
    
    public Circle(double radius) {
        super("Círculo");
        this.radius = radius;
    }
    
    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
    
    @Override
    public double perimeter() {
        return 2 * Math.PI * radius;
    }
}

public class Rectangle extends Shape {
    private double width, height;
    
    public Rectangle(double width, double height) {
        super("Retângulo");
        this.width = width;
        this.height = height;
    }
    
    @Override
    public double area() {
        return width * height;
    }
    
    @Override
    public double perimeter() {
        return 2 * (width + height);
    }
}

public class ShapeDemo {
    public static void main(String[] args) {
        Shape circle = new Circle(5);
        Shape rect = new Rectangle(4, 6);
        
        circle.display();  // Círculo - Área: 78.54, Perímetro: 31.42
        rect.display();    // Retângulo - Área: 24.0, Perímetro: 20.0
    }
}
▶ Experimente

Interfaces

Interfaces definem um conjunto de regras que as classes de implementação devem seguir.

Definição de Interface

JAVA
public interface NomeDaInterface {
    // Constantes (padrão public static final)
    int MAX_SIZE = 100;
    
    // Métodos abstratos (padrão public abstract)
    void method1();
    int method2(int a);
}

Implementação de Interface

JAVA
public class NomeDaClasse implements NomeDaInterface {
    @Override
    public void method1() {
        // Implementação
    }
    
    @Override
    public int method2(int a) {
        return a;
    }
}

Exemplo: Interface

JAVA
public interface Flyable {
    void fly();
}

public interface Swimmable {
    void swim();
}

public class Duck implements Flyable, Swimmable {
    @Override
    public void fly() {
        System.out.println("Pato está voando");
    }
    
    @Override
    public void swim() {
        System.out.println("Pato está nadando");
    }
}

public class InterfaceDemo {
    public static void main(String[] args) {
        Duck duck = new Duck();
        duck.fly();   // Pato está voando
        duck.swim();  // Pato está nadando
        
        // Referência de interface
        Flyable flyer = new Duck();
        flyer.fly();
    }
}
▶ Experimente

Interface vs Classe Abstrata

Característica Interface Classe Abstrata
Palavra-chave interface abstract class
Implementação implements extends
Múltipla implementação Suportado Não suportado
Construtores Nenhum Tem construtores
Variáveis de membro Apenas constantes Pode ter variáveis regulares
Métodos Métodos abstratos (pré-Java 8) Pode ter métodos regulares

Programação Orientada a Interface

JAVA
public interface Payment {
    void pay(double amount);
}

public class Alipay implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("Pagamento Alipay: $" + amount);
    }
}

public class WechatPay implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("Pagamento WeChat: $" + amount);
    }
}

public class PaymentDemo {
    // Programar para interface
    public static void checkout(Payment payment, double amount) {
        payment.pay(amount);
    }
    
    public static void main(String[] args) {
        checkout(new Alipay(), 100);      // Pagamento Alipay: $100.0
        checkout(new WechatPay(), 200);   // Pagamento WeChat: $200.0
    }
}

❓ Perguntas Frequentes

P: Quando devo usar classe abstrata vs interface? R: Use classes abstratas quando tiver estado e comportamento compartilhados. Use interfaces quando precisar apenas definir um contrato.

P: Interfaces podem ter corpos de métodos? R: Sim, desde o Java 8, você pode usar a palavra-chave default para definir métodos padrão.

P: Posso chamar métodos específicos do filho após upcasting? R: Não, você precisa fazer downcast (cast explícito) primeiro.

📖 Resumo

📝 Exercícios

  1. Hierarquia de animais: Defina uma classe abstrata Animal com subclasses Dog e Cat, implemente chamadas polimórficas
  2. Cálculos de formas: Defina uma interface Shape, implemente Circle e Rectangle, calcule áreas
  3. Sistema de pagamento: Defina uma interface Payment, implemente múltiplos métodos de pagamento

Próxima Lição

Na próxima lição, aprenderemos sobre Interfaces Avançadas e Lambda — características de interfaces e expressões Lambda.

100%