13  Herança

Especializar comportamento sem criar hierarquias frágeis

13.1 Objetivos de aprendizagem

Ao concluir este capítulo, você deverá ser capaz de:

  • reconhecer uma relação legítima de especialização;
  • inicializar a superclasse com super;
  • sobrescrever métodos com @Override;
  • usar classes abstratas;
  • justificar quando composição é preferível.

13.2 Relação é-um

Comando é a superclasse de ComandoAjuda e ComandoDica.

Uma hierarquia simples baseada em uma relação é-um.

Herança representa uma relação “é um”. Antes de usar extends, teste a frase “todo X é um Y” e confirme que a subclasse pode respeitar o contrato da superclasse.

abstract class MensagemBot {
    private final String categoria;

    protected MensagemBot(String categoria) {
        this.categoria = categoria;
    }

    public String getCategoria() {
        return categoria;
    }

    public abstract String texto();
}

final class Saudacao extends MensagemBot {
    Saudacao() {
        super("saudação");
    }

    @Override
    public String texto() {
        return "Olá! Vamos estudar Java?";
    }
}

final class Dica extends MensagemBot {
    Dica() {
        super("dica");
    }

    @Override
    public String texto() {
        return "Mantenha métodos pequenos e testáveis.";
    }
}

public class Capitulo12Heranca {
    public static void main(String[] args) {
        MensagemBot mensagem = new Dica();
        System.out.println(mensagem.getCategoria());
        System.out.println(mensagem.texto());
    }
}

A referência tem o tipo MensagemBot, mas o método executado pertence a Dica. Esse comportamento prepara o estudo de polimorfismo.

13.3 Construtores e super

Construtores não são herdados. A inicialização da superclasse ocorre antes da subclasse. Se a superclasse não tiver construtor sem parâmetros, a subclasse precisa chamar super(...).

Membros private continuam presentes no objeto, mas só são acessados pelos métodos da própria superclasse. Evite transformar atributos em protected apenas para facilitar acesso; prefira operações protegidas ou públicas que mantenham as invariantes.

13.4 Sobrescrita

@Override permite que o compilador confirme a intenção de sobrescrever. A assinatura deve ser compatível e a subclasse não deve enfraquecer o contrato esperado.

Sobrecarga e sobrescrita são diferentes:

  • sobrecarga: mesmo nome, parâmetros diferentes, decisão em compilação;
  • sobrescrita: mesma assinatura em uma subclasse, decisão em execução.

13.5 Classes abstratas e final

Uma classe abstrata representa um conceito incompleto e pode combinar estado, métodos concretos e métodos abstratos. Uma classe final bloqueia herança quando a extensão não foi planejada.

Não crie hierarquias profundas. Duas ou três camadas já exigem atenção; cadeias maiores tornam alterações e testes mais difíceis.

13.6 Quando preferir composição

  • Carro tem um motor: composição.
  • Chatbot tem um histórico: composição.
  • Dica é uma mensagem do bot: herança pode ser adequada.

Se o objetivo é apenas reutilizar algumas linhas, herança provavelmente é a ferramenta errada.

O exemplo completo está em examples/src/Capitulo12Heranca.java.

13.7 Prática verificável

Crie uma nova subclasse Aviso que devolva uma mensagem de atenção. Depois, responda:

  1. qual estado pertence à superclasse?
  2. qual comportamento foi sobrescrito?
  3. a substituição de Dica por Aviso mantém o programa válido?
  4. seria melhor modelar esse caso com composição?
AvisoHerança não é cópia de código

Use herança para representar substituição comportamental, não como mecanismo automático de reúso.