Herança é o mecanismo pelo qual uma classe (subclasse/classe filha) pode estender outra classe (superclasse/classe mãe), aproveitando seus comportamentos (métodos) e características (atributos).
A classe herdeira é chamada de classe filha ou subclasse, enquanto a classe que é herdada é chamada de classe mãe ou superclasse.
Permite que conceitos (classes) e seus elementos mais específicos incorporem a estrutura e o comportamento de conceitos e seus elementos mais genéricos.
Promove a reutilização de atributos e métodos de uma classe por outra. Isso pode simplificar o projeto do código, tornando-o mais modular e fácil de manter.
Além disso, a herança ajuda a evitar a repetição de código, pois as subclasses não precisam redefinir os métodos e atributos que já foram definidos na superclasse.
Classes herdeiras (subclasses/classe filhas) de atributos/métodos podem possuir atributos e métodos próprios, além dos herdados.
A herança permite que subclasses herdem características e comportamentos da sua superclasse.
Fonte: Autoral, feito com Canva para Educação.
public class Animal {
public void comer() {
System.out.println("O animal está comendo...");
}
}
public class Cachorro extends Animal {
public void latir() {
System.out.println("O cachorro está latindo!");
}
}
public class Gato extends Animal {
public void miar() {
System.out.println("O gato está miando!");
}
}
Por exemplo, em uma relação de herança entre as classes Usuario, Estudante e Docente, ambas classes filhas (Estudante e Docente) possuem atributos como CPF, nome, data de nascimento e o método de atualizar dados. Porém, elas também apresentam atributos e métodos específicos, conforme a ilustração a seguir.
Em Java NÃO existe herança múltipla, ou seja:
Uma superclasse pode ter várias subclasses, mas
Uma subclasse pode ter apenas uma superclasse direta.
Outras linguagens, como a C# e Ruby também não permitem o conceito de herança múltipla. Porém, este conceito está presente em outras linguagens orientadas a objetos como, C++, Python e Perl.
A palavra reservada extends indica que a classe a ser descrita herda de outra classe.
No caso, a classe B herda/estende/é filha/é subclasse da classe A.
class A {
//conteúdo da classe A
}
class B extends A {
//conteúdo da classe B
}
public class Usuario {
protected String CPF, nome, dataNascimento;
Usuario() {
System.out.println("Novo objeto usuário criado!");
}
public String getCPF() {
return CPF;
}
public void setCPF(String CPF) {
this.CPF = CPF;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getDataNascimento() {
return dataNascimento;
}
public void setDataNascimento(String dataNascimento) {
this.dataNascimento = dataNascimento;
}
public void atualizarDados() {
System.out.println("Exemplo de método que será herdado por filhas da classe Usuario.");
}
}
public class Estudante extends Usuario {
protected String RGA;
Estudante() {
System.out.println("Novo objeto estudante criado!");
}
public String getRGA() {
return RGA;
}
public void setRGA(String RGA) {
this.RGA = RGA;
}
public void verHistorico() {
System.out.println("Exemplo de método da classe Estudante.");
}
}
public class Docente extends Usuario {
protected String SIAPE;
Docente() {
System.out.println("Novo objeto docente criado!");
}
public String getSIAPE() {
return SIAPE;
}
public void setSIAPE(String SIAPE) {
this.SIAPE = SIAPE;
}
public void verEncargos() {
System.out.println("Exemplo de método da classe Docente.");
}
}
Disponível em: https://replit.com/@professorakarenribeiro/AcademicoHeranca
A criação de objetos pode ser feita diretamente pela criação da instância da subclasse OU indiretamente pela atribuição da instância da subclasse na superclasse.
class Main {
public static void main(String[] args) {
Usuario u01, u02;
u01 = new Usuario(); //Instanciamento direto
u02 = new Estudante(); //Instanciamento indireto
Docente u03 = new Docente(); //Instanciamento direto
}
}
Diminui a quantidade de código através do reuso;
Promove maior integridade do projeto orientado a objetos, ou seja, classes mais coesas e com encapsulamento adequado;
Permite arquiteturas mais robustas;
Permite que as alterações no código da classe mãe/superclasse sejam compartilhadas com todas as suas classes herdeiras, facilitando a manutenção.
Conforme visto anteriormente, quando definimos um método construtor para uma classe em Java, ele sobrescreve o método construtor default que "apenas" cria um objeto da classe, ou seja, o método construtor definido substitui o método construtor default.
O mesmo acontece quando escrevemos um método construtor para uma subclasse, ele sobrescreve o método construtor da superclasse.
Quando uma subclasse é instanciada, o método construtor da superclasse também é executado. A subclasse pode chamar explicitamente o construtor da superclasse usando a palavra reservada super.
public class Animal {
public Animal() {
System.out.println("Método construtor de animal");
}
}
public class Cachorro extends Animal {
public Cachorro() {
System.out.println("Método construtor de cachorro");
}
}
public class Gato extends Animal {
public Gato() {
System.out.println("Método construtor de gato");
}
}
Arquivo Usuario.java
public class Usuario {
protected String CPF, nome, dataNascimento;
Usuario(String CPF, String nome, String dataNascimento) {
this.setCPF(CPF);
this.setNome(nome);
this.setDataNascimento(dataNascimento);
System.out.println("Novo objeto usuário criado com seus dados!");
}
...
Arquivo Estudante.java
public class Estudante extends Usuario {
protected String RGA;
Estudante(String CPF, String nome, String dataNascimento, String RGA) {
super(CPF, nome, dataNascimento);
this.setRGA(RGA);
System.out.println("Objeto do tipo estudante com RGA");
}
...
Arquivo Docente.java
public class Docente extends Usuario {
protected String SIAPE;
Docente(String CPF, String nome, String dataNascimento, String SIAPE) {
super(CPF, nome, dataNascimento);
this.setSIAPE(SIAPE);
System.out.println("Objeto do tipo docente com SIAPE");
}
...
Assim, como a palavra reservada this é utilizada para referência o próprio contexto (objeto/classe), a palavra reservada super permite às subclasses referenciar métodos e atributos do contexto da sua superclasse.
No exemplo, super é usado para chamar o método construtor da superclasse e depois segue complementando-o com novas instruções que são específicas para a subclasse.
Em uma herança, outros métodos da superclasse, além do método construtor, também podem ser sobrescritos nas subclasses.
A sobrescrita de métodos é muito importante para alterar e adicionar novos comportamentos para as classes mais baixas da hierarquia, permitindo a aplicação de comportamentos específicos para classes específicas.
public class Animal {
public void falar() {
System.out.println("O animal está falando");
}
}
public class Cachorro extends Animal {
public void falar() {
System.out.println("Au, au!");
}
}
public class Gato extends Animal {
public void falar() {
System.out.println("Miau!");
}
}
Arquivo Usuario.java
public class Usuario {
protected String CPF, nome, dataNascimento;
Usuario(String CPF, String nome, String dataNascimento) {
this.setCPF(CPF);
this.setNome(nome);
this.setDataNascimento(dataNascimento);
System.out.println("Novo objeto usuário criado com seus dados!");
}
...
public void atualizarDados() {
System.out.println("Exemplo de método que será herdado por filhas da classe Usuario.");
}
...
Arquivo Docente.java
public class Docente extends Usuario {
protected String SIAPE;
Docente(String CPF, String nome, String dataNascimento, String SIAPE) {
super(CPF, nome, dataNascimento);
this.setSIAPE(SIAPE);
System.out.println("Objeto do tipo docente com SIAPE");
}
...
@Override
public void atualizarDados() {
System.out.println("Método sobrescrito");
}
...
Anotações são formas de introduzir metadados no código, e na linguagem Java sua sintaxe é defina pelo símbolo "@".
Anotações são úteis para adicionar mais semântica ao código, principalmente, quando trabalha-se com tarefas automatizadas. Ex.: manipulação de arquivos de configuração XML, configuração de webservices etc.
Na sobrescrita, utiliza-se a anotação @Override. A anotação @Override permite especificar que um método sobrescreve outro método da superclasse. Dessa forma, o compilador tem como assegurar que o comportamento indicado na anotação realmente acontece no código.
DICA: A maioria das IDEs tem opções para geração automática das anotações importantes reconhecidas na comunidade.
Até o momento, trabalhamos com os modificadores de acesso público (public) e privado (private).
Quando trabalha-se com herança, é possível também utilizar um modificador de acesso próprio protegido: protected .
protected é usado em uma relação de herança a fim de manter a comunicação entre a família de classes, sem abrir totalmente mão da privacidade (encapsulamento) fora dela.
Uma subclasse tem acesso apenas aos atributos e métodos definidos na superclasse com visibilidade public e protected, mas não private.
Atributos protected podem ser acessados diretamente pelas subclasses, sem a necessidade de métodos getters e setters.
Na sobrescrita de métodos é importante ressaltar que o modificador de acesso do método que sobrescreve não deve restringir o modificador de acesso do método da superclasse.
Modificadores de acesso na sobrescrita de métodos em uma herança não devem ser restringidos.
Fonte: Autoral, feito com Canva para Educação.
Toda subclasse pode vir a tornar-se uma superclasse para novas subclasses, criando assim uma hierarquia de classes
A superclasse direta é aquela a partir da qual a subclasse herda explicitamente, uma superclasse indireta é qualquer superclasse acima da classe direta na hierarquia de classes
Com a herança é possível definir uma hierarquia de vários níveis. Fonte: Autoral, feito com Canva para Educação.
Arquivo Usuario.java
public class Estudante extends Usuario {
protected String RGA;
Estudante() {
System.out.println("Novo objeto estudante criado!");
}
...
Arquivo EstudanteGraduacao.java
public class EstudanteGraduacao extends Estudante {
EstudanteGraduacao() {
System.out.println("Novo objeto estudante de graduação criado!");
}
}
Arquivo EstudantePosGraduacao.java
public class EstudantePosGraduacao extends Estudante {
EstudantePosGraduacao() {
System.out.println("Novo objeto estudante de pós-graduação criado!");
}
}