Lições do módulo (2/2)
Polimorfismo e classes abstratas
Polimorfismo e classes abstratas são conceitos avançados de programação orientada a objetos que nos permitem escrever código flexível e extensível, independente de implementações específicas.
Polimorfismo
O termo polimorfismo (muitas formas) refere-se à capacidade de tratar objetos de diferentes classes como se pertencessem a um tipo comum. Em Java, uma variável de referência de superclasse pode armazenar uma referência a um objeto de qualquer uma de suas subclasses.
class Animal {
public void makeSound() {
System.out.println("Verso...");
}
}
class Dog extends Animal {
public void makeSound() {
System.out.println("Woof");
}
}
class Cat extends Animal {
public void makeSound() {
System.out.println("Miao");
}
}Graças ao polimorfismo, podemos fazer isso:
Animal myAnimal1 = new Dog(); // Polymorphism
Animal myAnimal2 = new Cat(); // Polymorphism
myAnimal1.makeSound(); // Executes Dog's method (Woof)
myAnimal2.makeSound(); // Executes Cat's method (Miao)A decisão sobre qual método invocar é feita em tempo de execução (Late Binding ou despacho dinâmico) com base no objeto real, não no tipo da variável de referência.
Classes abstratas (abstract)
Uma classe abstrata é uma classe marcada com a palavra-chave abstract que não pode ser instanciada diretamente (você não pode fazer new MyAbstractClass()). Serve como um "modelo parcial" para outras classes.
Métodos Abstratos
Uma classe abstrata pode conter métodos abstratos: métodos declarados sem corpo (sem chaves e sem código), terminando com ponto e vírgula. Subclasses não abstratas são necessárias para implementar todos os métodos abstratos herdados.
abstract class Shape {
String color;
// Abstract method (no body)
public abstract double getArea();
}
class Circle extends Shape {
double radius;
public Circle(double radius) {
this.radius = radius;
}
// Required to implement getArea
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}Vinculação dinâmica/vinculação tardia
Como o Java sabe qual método executar em tempo de execução? Este processo é conhecido como Late Binding (ou Dynamic Binding). Ao contrário da sobrecarga (que é resolvida em tempo de compilação), o compilador não sabe qual método específico será executado. Em vez disso, gera uma instrução de chamada genérica. Em tempo de execução, a Java Virtual Machine (JVM) inspeciona o objeto real na memória e invoca a implementação do método definido na classe desse objeto.
Classes abstratas e implementação ausente
Se uma subclasse herda de uma classe abstrata, ela tem duas opções:
- Implementar todos os métodos abstratos: neste caso, a subclasse pode ser uma classe normal (concreta) e pode ser instanciada.
- Declarar-se abstrato: se a subclasse não fornece uma implementação para todos os métodos abstratos herdados, ela também deve ser declarada com a palavra-chave
abstract.
abstract class Animal {
public abstract void makeSound();
}
// This class MUST be abstract because it does not implement makeSound()
abstract class Canine extends Animal {
// Inherits makeSound() but does not implement it
}Experimente você mesmo
Declare uma variável s do tipo Shape e atribua a ela um novo objeto Circle usando polimorfismo.
Mostrar dica
Escreva `Shape s = new Circle();` para usar o tipo base como tipo de referência.
Solução disponível após 3 tentativas
Torne a classe Shape abstrata e adicione o método abstrato double getArea(). Em seguida, complete Square para que ele estenda Shape e implemente getArea() retornando side * side.
Mostrar dica
Declare `public abstract double getArea();` no Shape. No Square, adicione `@Override public double getArea() { return side * side; }`.
Solução disponível após 3 tentativas
Declare no método principal um array do tipo Shape[] contendo um objeto Circle com raio 2,0 e um objeto Square com lado 3,0. Em seguida, use um loop (for ou for-each) para imprimir a área de cada forma invocando o método getArea().
Mostrar dica
Declare o array com `Shape[] formas = { new Circle(2.0), new Square(3.0) };` e faça um loop por ele usando `for (Shape s : Shapes)` imprimindo `s.getArea()`.
Solução disponível após 3 tentativas