13.6 Herança e Polimorfismo em Java: Construtores e Herança
A herança é um dos pilares da Programação Orientada a Objetos (POO) e permite que uma classe herde características de outra classe. Em Java, a herança é implementada com a palavra-chave extends
. Polimorfismo, por outro lado, é a capacidade de um método ter várias formas, ou seja, um mesmo método pode comportar-se de maneira diferente dependendo do contexto em que é chamado. Ambos os conceitos são fundamentais para a criação de aplicações flexíveis e reutilizáveis.
Construtores e Herança
Quando falamos sobre construtores em um contexto de herança, é importante entender como os construtores da classe base (superclasse) são afetados pela classe derivada (subclasse). Em Java, a primeira tarefa de qualquer construtor da subclasse é chamar um construtor da superclasse. Se não fizermos isso explicitamente, o compilador tentará chamar o construtor padrão (sem argumentos) da superclasse. Se a superclasse não tiver um construtor padrão, teremos que chamar explicitamente um construtor existente usando a palavra-chave super
.
public class Superclasse {
public Superclasse() {
// Construtor padrão
}
public Superclasse(int arg) {
// Construtor com argumentos
}
}
public class Subclasse extends Superclasse {
public Subclasse() {
super(); // Chama o construtor padrão da Superclasse
}
public Subclasse(int arg) {
super(arg); // Chama o construtor com argumentos da Superclasse
}
}
Note que se você não chamar explicitamente o construtor da superclasse usando super()
, o compilador o fará por você, desde que um construtor padrão esteja disponível. Se a superclasse não tiver um construtor padrão e o programador não chamar outro construtor explicitamente, o compilador emitirá um erro.
Herança e Encapsulamento
A herança também deve ser usada com cautela em relação ao encapsulamento. Se uma classe base tem campos privados, estes não são acessíveis diretamente pela subclasse. A subclasse pode acessar esses campos apenas através de métodos públicos ou protegidos (com a palavra-chave protected
) da classe base. Isso é importante para manter a integridade dos dados e a abstração da classe base.
Polimorfismo
O polimorfismo em Java é obtido principalmente através do método de sobrescrita (override). Quando uma subclasse fornece uma implementação específica para um método que já existe na superclasse, dizemos que o método foi sobrescrito. Isso permite que uma referência de tipo da superclasse possa apontar para um objeto do tipo da subclasse e que a versão correta do método seja chamada, conforme o tipo do objeto.
public class Animal {
public void emitirSom() {
System.out.println("O animal emite um som");
}
}
public class Cachorro extends Animal {
@Override
public void emitirSom() {
System.out.println("O cachorro late");
}
}
public class Main {
public static void main(String[] args) {
Animal meuAnimal = new Cachorro();
meuAnimal.emitirSom(); // Saída: O cachorro late
}
}
Nesse exemplo, mesmo que a referência meuAnimal
seja do tipo Animal
, o método emitirSom()
que é chamado é o da classe Cachorro
, pois o objeto real é um Cachorro
. Isso é uma demonstração de polimorfismo em ação.
Considerações Finais
A herança e o polimorfismo são fundamentais para a reutilização de código e para a construção de sistemas que são fáceis de manter e expandir. No entanto, esses conceitos devem ser usados com discernimento. A herança pode levar a hierarquias de classes complicadas e difíceis de entender se não for bem planejada. O polimorfismo, embora poderoso, pode tornar o código mais difícil de seguir, pois o comportamento exato do código pode não ser claro à primeira vista.
É importante lembrar que a herança deve ser aplicada apenas quando uma relação "é um" faz sentido. Usar herança para reutilizar código pode ser tentador, mas pode levar a uma estrutura de classes inadequada. Composição, ou seja, usar objetos de outras classes como campos, muitas vezes é uma alternativa melhor à herança.
Em resumo, herança e polimorfismo são ferramentas poderosas na caixa de ferramentas de um programador Java, mas como todas as ferramentas, elas devem ser usadas corretamente para obter os melhores resultados. Entender como os construtores interagem com a herança é um passo importante para dominar esses conceitos e criar aplicações robustas e flexíveis.