Herança

A herança é um mecanismo que permite estender uma classe sem modificar a classe original. Isso tem diversos benefícios que serão estudados posteriormente. Considere a classe Emprestimo que desenvolvemos na etapa anterior. O modificador de acesso dos atributos foi alterado para protected; explicaremos isso a seguir.


In [1]:
class Emprestimo {
    protected float s;
    protected int   n;
    protected float j;
    protected int   corrente;
    protected float p;

    public Emprestimo(float s, int n, float j) {
        this.s = s;
        this.n = n;
        this.j = j;
        corrente = 1;
        this.p = s;
    }

    public float proximaParcela() {
        float retorno = p;
        corrente++;
        if (corrente <= n)
            p = p + (p * (j/100));
        else
            p = 0;
        return retorno;
    }
}

// codigo principal

Emprestimo emprestimo1 = new Emprestimo(200, 5, 1),
           emprestimo2 = new Emprestimo(500, 7, 2);

int i = 1;
float p1 = emprestimo1.proximaParcela();
float p2 = emprestimo2.proximaParcela();
while (p1 > 0 || p2 > 0) {
    if (p1 > 0)
        System.out.println("Emprestimo 1: parcela " + i + " eh " + p1);
    if (p2 > 0)
        System.out.println("Emprestimo 2: parcela " + i + " eh " + p2);
    p1 = emprestimo1.proximaParcela();
    p2 = emprestimo2.proximaParcela();
    i++;
}


Emprestimo 1: parcela 1 eh 200.0
Emprestimo 2: parcela 1 eh 500.0
Emprestimo 1: parcela 2 eh 202.0
Emprestimo 2: parcela 2 eh 510.0
Emprestimo 1: parcela 3 eh 204.02
Emprestimo 2: parcela 3 eh 520.2
Emprestimo 1: parcela 4 eh 206.06021
Emprestimo 2: parcela 4 eh 530.604
Emprestimo 1: parcela 5 eh 208.12082
Emprestimo 2: parcela 5 eh 541.21606
Emprestimo 2: parcela 6 eh 552.0404
Emprestimo 2: parcela 7 eh 563.08124

Classe herdeira

Suponha que você quer criar uma classe herdeira chamada EmprestimoPlus. Essa classe acrescenta um método totalPagar que é capaz de calcular o valor total que será pago no empréstimo.

Para criar a classe herdeira basta usar a cláusula extends:

public class EmprestimoPlus extends Emprestimo

Como os atributos estavam private, nem mesmo a classe herdeira pôde acessá-los. O modificador protected permite que os herdeiros acessem os atributos (mas não objetos externos).

A classe herdeira herda os atributos e métodos da superclasse e pode usá-los como se fossem dela, sem a necessidade de alguma referência específica.

Há casos especiais que a classe herdeira e a superclasse têm métodos com o mesmo nome (estudaremos adiante) ou quando se trata do construtor, porque a classe herdeira pode ter dúvidas se uma chamada de método se refere a classe corrente ou superclasse. Portanto, somente para casos especiais, há um jeito de fazer referência explícita à superclasse usando super.

Note que o construtor da classe EmprestimoPluschama o método super. A cláusula super faz referência à superclasse. Quando super é acionado como método sozinho ele se refere ao construtor da superclasse. O método super seguido do nome de um método, por exemplo, super.metodo() aciona o método especificado da superclasse.

Só é necessário usar o super quando há dúvida. A classe herdeira tem acesso a todos os métodos da superclasse sem a necessidade de dizer que o método é da superclasse.


In [2]:
public class EmprestimoPlus extends Emprestimo {
    public EmprestimoPlus(float s, int n, float j) {
        super(s, n, j);
    }
    
    public float totalPagar() {
        float total = 0,
              parcela = p;
        
        for (int i = 1; i < n; i++) {
            total += parcela;
            parcela = parcela + (parcela * (j/100));
        }
        
        return total;        
    }
}

EmprestimoPlus emprestimo1 = new EmprestimoPlus(200, 5, 1),
               emprestimo2 = new EmprestimoPlus(500, 7, 2);
System.out.println("Total a pagar Emprestimo 1: " + emprestimo1.totalPagar());
System.out.println("Total a pagar Emprestimo 2: " + emprestimo2.totalPagar());


Total a pagar Emprestimo 1: 812.0802
Total a pagar Emprestimo 2: 3154.0605

Evitando o protected

Alguns especialistas não gostam do uso do protected, como discutiremos adiante. Modifique as classes Emprestimo e EmprestimoPlus de modo que a classe EmprestimoPlus consiga acessa os atributos de Emprestimo sem o uso de public nem protected neles.


In [ ]:

Herança com Garoto Zumbi

Crie duas classes herdeiras de GarotoZumbi com as seguintes funcionalidades:

  • Monstro - Consegue crescer mais que o GarotoZumbi (até cinco anos de idade). Monstro também pode estar dormindo ou acordado em qualquer uma das idades.
o*o

  *
 o*o

  *
 o*o
*****

  *
 o*o
*****
#####

  *
 o*o
*****
#####
/   \
  • Perfeito - Tem outra aparência e tem dois outros estados milionario e doido, que muda a aparência dos olhos (vide exemplo abaixo). Os dois novos estados devem se aplicar a todas as idades. Ele também acrescenta um método chamado mudaEstado() que muda o estado (ciclicamente) entre normal, milionario e doido. Cada vez que o Perfeito muda de estado, o novo estado é automaticamente mostrado. O Perfeito não tem os estados acordado e dormindo.
+-----+
| o-o |
| ___ |
 \___/
1 ano
+-----+
|     |
| o-o |
| ___ |
 \___/
2 anos
+-----+
|     |
| o-o |
| ___ |
|     |
\_____/
3 anos (limite)
+-----+
|     |
| $-$ |
| ___ |
|     |
\_____/
milionário
+-----+
|     |
| @-@ |
|  ~  |
|     |
\_____/
doido

Dica importante para o Monstro: quando você coloca a contrabarra (\) dentro das aspas ela se comporta como escape, portanto, para representar uma contrabarra em vez de um escape são necessárias duas contrabarras (\\).


In [3]:
public class GarotoZumbi
{
    protected int idade;
    protected String estado;
    protected String nome;
    
    public GarotoZumbi(int idade, String estado, String nome) {
        this.idade = idade;
        this.estado = estado;
        this.nome = nome;
    }
    
    public void mostra() {
        // cabeleira
        if (idade >= 2)
            System.out.println("  *");
        
        // corpo com olhos
        if (estado.equalsIgnoreCase("acordado"))
            System.out.println(" o*o");
        else
            System.out.println(" -*-");
        
        // barba
        if (idade >= 3)
            System.out.println("*****");
        
        System.out.println(nome);
        
        System.out.println();
    }
    
    public void cresce() {
        if (idade < 3)
            idade++;
        mostra();
    }
    
    public void acorda() {
        estado = "acordado";
        mostra();
    }
    
    public void dorme() {
        estado = "dormindo";
        mostra();
    }
}

GarotoZumbi garoto = new GarotoZumbi(1, "acordado", "Asdrubal");
garoto.mostra();
garoto.dorme();
garoto.cresce();


 o*o
Asdrubal

 -*-
Asdrubal

  *
 -*-
Asdrubal