image

Acesse bootcamps ilimitados e +650 cursos

50
%OFF

JA

Jhonatan Araujo04/08/2025 15:02
Compartilhe
Suzano - Python Developer #2Recomendados para vocêSuzano - Python Developer #2

Herança em Java: Guia Completo de Programação Orientada a Objetos

  • #Java
  • #Orientação a objetos, classes e métodos
  • #POO

image

Herança em Java: Guia Completo de Programação Orientada a Objetos

Introdução à Herança em Java

herança é um dos pilares fundamentais da programação orientada a objetos (POO) em Java. Este conceito permite que uma classe filha herde características (atributos e métodos) de uma classe pai, promovendo a reutilização de código e criando hierarquias lógicas entre classes relacionadas.

Neste guia completo, você aprenderá tudo sobre herança em Java, desde conceitos básicos até implementações avançadas, com exemplos práticos que você pode usar em seus projetos.

O que é Herança em Java?

A herança em Java é um mecanismo que permite criar uma nova classe baseada em uma classe existente. A classe que é herdada é chamada de superclasse (ou classe pai), enquanto a classe que herda é chamada de subclasse (ou classe filha).

Vantagens da Herança

  • Reutilização de código: Evita duplicação de código comum
  • Manutenibilidade: Facilita a manutenção e atualização do código
  • Extensibilidade: Permite adicionar novas funcionalidades facilmente
  • Polimorfismo: Habilita o uso de polimorfismo em Java
  • Organização: Cria hierarquias lógicas e organizadas

Sintaxe Básica da Herança em Java

A palavra-chave extends é utilizada para implementar herança em Java:

public class ClassePai {
  // Atributos e métodos da classe pai
}

public class ClasseFilha extends ClassePai {
  // Atributos e métodos específicos da classe filha
  // Herda automaticamente tudo da classe pai
}

Exemplo Prático: Sistema de Veículos

Vamos criar um exemplo completo de herança com um sistema de veículos:

Classe Pai (Superclasse)

public class Veiculo {
  protected String marca;
  protected String modelo;
  protected int ano;
  protected double velocidadeAtual;
  
  // Construtor
  public Veiculo(String marca, String modelo, int ano) {
      this.marca = marca;
      this.modelo = modelo;
      this.ano = ano;
      this.velocidadeAtual = 0.0;
  }
  
  // Métodos comuns a todos os veículos
  public void acelerar(double incremento) {
      this.velocidadeAtual += incremento;
      System.out.println("Acelerando... Velocidade atual: " + velocidadeAtual + " km/h");
  }
  
  public void frear(double decremento) {
      this.velocidadeAtual = Math.max(0, velocidadeAtual - decremento);
      System.out.println("Freando... Velocidade atual: " + velocidadeAtual + " km/h");
  }
  
  public void exibirInfo() {
      System.out.println("Marca: " + marca + ", Modelo: " + modelo + ", Ano: " + ano);
  }
  
  // Getters e Setters
  public String getMarca() { return marca; }
  public String getModelo() { return modelo; }
  public int getAno() { return ano; }
  public double getVelocidadeAtual() { return velocidadeAtual; }
}

Classes Filhas (Subclasses)

public class Veiculo {
  protected String marca;
  protected String modelo;
  protected int ano;
  protected double velocidadeAtual;
  
  // Construtor
  public Veiculo(String marca, String modelo, int ano) {
      this.marca = marca;
      this.modelo = modelo;
      this.ano = ano;
      this.velocidadeAtual = 0.0;
  }
  
  // Métodos comuns a todos os veículos
  public void acelerar(double incremento) {
      this.velocidadeAtual += incremento;
      System.out.println("Acelerando... Velocidade atual: " + velocidadeAtual + " km/h");
  }
  
  public void frear(double decremento) {
      this.velocidadeAtual = Math.max(0, velocidadeAtual - decremento);
      System.out.println("Freando... Velocidade atual: " + velocidadeAtual + " km/h");
  }
  
  public void exibirInfo() {
      System.out.println("Marca: " + marca + ", Modelo: " + modelo + ", Ano: " + ano);
  }
  
  // Getters e Setters
  public String getMarca() { return marca; }
  public String getModelo() { return modelo; }
  public int getAno() { return ano; }
  public double getVelocidadeAtual() { return velocidadeAtual; }
}

Testando a Herança

public class TesteHeranca {
  public static void main(String[] args) {
      // Criando objetos das classes filhas
      Carro meuCarro = new Carro("Toyota", "Corolla", 2023, 4, "Flex");
      Moto minhaMoto = new Moto("Honda", "CB600F", 2022, 600, true);
      
      System.out.println("=== INFORMAÇÕES DOS VEÍCULOS ===");
      meuCarro.exibirInfo();
      System.out.println();
      minhaMoto.exibirInfo();
      
      System.out.println("\n=== TESTANDO MÉTODOS HERDADOS ===");
      meuCarro.acelerar(50);
      minhaMoto.acelerar(30); // Comportamento sobrescrito
      
      System.out.println("\n=== MÉTODOS ESPECÍFICOS ===");
      meuCarro.ligarArCondicionado();
      minhaMoto.empinar();
      
      // Demonstrando polimorfismo
      System.out.println("\n=== POLIMORFISMO ===");
      Veiculo[] veiculos = {meuCarro, minhaMoto};
      
      for (Veiculo veiculo : veiculos) {
          veiculo.exibirInfo(); // Chama o método sobrescrito de cada classe
          System.out.println("---");
      }
  }
}

Conceitos Avançados de Herança

1. Modificadores de Acesso

public class Exemplo {
  public String publico;        // Acessível de qualquer lugar
  protected String protegido;   // Acessível na mesma package e subclasses
  private String privado;       // Acessível apenas na própria classe
  String pacote;               // Acessível apenas na mesma package
}

2. Palavra-chave Super

A palavra-chave super é fundamental na herança:

public class Funcionario {
  protected String nome;
  protected double salario;
  
  public Funcionario(String nome, double salario) {
      this.nome = nome;
      this.salario = salario;
  }
  
  public double calcularBonus() {
      return salario * 0.1; // 10% do salário
  }
}

public class Gerente extends Funcionario {
  private String departamento;
  
  public Gerente(String nome, double salario, String departamento) {
      super(nome, salario); // Chama construtor da superclasse
      this.departamento = departamento;
  }
  
  @Override
  public double calcularBonus() {
      // Gerentes têm bônus maior
      return super.calcularBonus() * 2; // Chama método da superclasse
  }
}

3. Classes Abstratas e Herança

public abstract class Animal {
  protected String nome;
  
  public Animal(String nome) {
      this.nome = nome;
  }
  
  // Método concreto
  public void dormir() {
      System.out.println(nome + " está dormindo");
  }
  
  // Método abstrato - deve ser implementado pelas subclasses
  public abstract void emitirSom();
}

public class Cachorro extends Animal {
  public Cachorro(String nome) {
      super(nome);
  }
  
  @Override
  public void emitirSom() {
      System.out.println(nome + " faz: Au au!");
  }
}

Boas Práticas na Herança Java

1. Princípio da Substituição de Liskov

As subclasses devem ser substituíveis por suas superclasses sem quebrar a funcionalidade:

public class ContaBancaria {
  protected double saldo;
  
  public void sacar(double valor) {
      if (valor <= saldo) {
          saldo -= valor;
      }
  }
  
  public double getSaldo() {
      return saldo;
  }
}

public class ContaPoupanca extends ContaBancaria {
  @Override
  public void sacar(double valor) {
      // Mantém o contrato da superclasse
      if (valor <= saldo && valor <= 1000) { // Limite adicional
          super.sacar(valor);
      }
  }
}

2. Evitar Herança Profunda

Prefira composição quando a hierarquia ficar muito complexa:

// Em vez de herança profunda, use composição
public class Veiculo {
  private Motor motor; // Composição
  private Rodas rodas; // Composição
  
  public Veiculo(Motor motor, Rodas rodas) {
      this.motor = motor;
      this.rodas = rodas;
  }
}

Herança vs Composição: Quando Usar?

Use Herança quando:

  • Existe uma relação "é um" clara
  • Você quer aproveitar polimorfismo
  • A hierarquia é estável e bem definida

Use Composição quando:

  • A relação é "tem um" ou "usa um"
  • Você precisa de maior flexibilidade
  • A hierarquia pode mudar frequentemente

Limitações da Herança em Java

1. Herança Simples

Java permite apenas herança simples de classes (uma classe só pode estender uma superclasse):

// Isto NÃO é permitido em Java
// public class MinhaClasse extends Classe1, Classe2 { } 

// Use interfaces para múltipla herança de comportamento
public interface Voador {
  void voar();
}

public interface Nadador {
  void nadar();
}

public class Pato implements Voador, Nadador {
  @Override
  public void voar() {
      System.out.println("Pato voando");
  }
  
  @Override
  public void nadar() {
      System.out.println("Pato nadando");
  }
}
}

Exercícios Práticos

Exercício 1: Sistema de Funcionários

Crie uma hierarquia de classes para representar diferentes tipos de funcionários (Desenvolvedor, Designer, Gerente) que herdem de uma classe Funcionario base.

Exercício 2: Formas Geométricas

Implemente uma hierarquia de formas geométricas (Círculo, Retângulo, Triângulo) que herdem de uma classe abstrata Forma com métodos para calcular área e perímetro.

Conclusão

A herança é um conceito fundamental na programação orientada a objetos em Java que oferece poderosas capacidades de reutilização e organização de código. Compreender seus princípios, sintaxe e boas práticas é essencial para todo desenvolvedor Java.

Lembre-se de sempre avaliar se a herança é a melhor solução para seu problema específico, considerando alternativas como composição quando apropriado. A herança bem implementada resulta em código mais limpo, manutenível e extensível.

Palavras-chave: herança java, programação orientada objetos, POO java, extends java, super java, override java, polimorfismo java, classes abstratas java, subclasse java, superclasse java, reutilização código java, tutorial herança java

Back Java Total

Compartilhe
Recomendados para você
Riachuelo - Primeiros Passos com Java
GFT Start #7 - Java
NTT DATA - Java e IA para Iniciantes
Comentários (1)
DIO Community
DIO Community - 04/08/2025 17:16

Excelente, Jhonatan! Que artigo incrível e super completo sobre "Herança em Java: Guia Completo de Programação Orientada a Objetos"! É fascinante ver como você aborda a herança como um dos pilares da POO, que permite que uma classe filha herde características de uma classe pai, promovendo a reutilização de código e criando hierarquias lógicas entre classes relacionadas.

Você demonstrou as vantagens da herança (reutilização, manutenibilidade, extensibilidade), a sintaxe básica com extends e a aplicação prática em um sistema de veículos. Sua análise de conceitos avançados, como modificadores de acesso, a palavra-chave super, classes abstratas e a distinção entre herança e composição, é um guia fundamental para qualquer desenvolvedor Java.

Considerando que "a herança bem implementada resulta em código mais limpo, manutenível e extensível", mas que "é preciso avaliar se a herança é a melhor solução", qual você diria que é o maior desafio para um desenvolvedor ao decidir entre usar herança ou composição para modelar um sistema, em termos de promover a reutilização de código sem criar um acoplamento indesejado que possa dificultar a manutenção do software a longo prazo?

Recomendados para vocêSuzano - Python Developer #2