Desafio Java

Herança com classe final e método final

Enunciado

Crie uma classe ContaBancaria com atributos titular e saldo, e métodos depositar(double valor) e sacar(double valor). O método sacar deve ser final para impedir sobrescrita. Crie uma subclasse ContaPoupanca que estende ContaBancaria e adiciona o método renderJuros(double taxa). No main, crie uma ContaPoupanca, deposite, saque e renda juros, imprimindo o saldo final. Tente estender ContaPoupanca? Não, marque ContaPoupanca como final para impedir herança.

Requisitos

  • A classe ContaBancaria deve ter construtor que recebe titular e saldo inicial.
  • O método sacar deve ser final e não pode ser sobrescrito.
  • A classe ContaPoupanca deve ser final e ter o método renderJuros(double taxa).
  • O programa deve imprimir o saldo após as operações.

Código inicial

class ContaBancaria {
    // seu código aqui
}

final class ContaPoupanca extends ContaBancaria {
    // seu código aqui
}

public class Main {
    public static void main(String[] args) {
        // realize as operações e imprima o saldo
    }
}

Saída esperada

Saldo final: 1100.0
Ver dica

Use final no método sacar e na classe ContaPoupanca. Lembre-se de que renderJuros deve aumentar o saldo.

Mostrar solução
class ContaBancaria {
    protected String titular;
    protected double saldo;

    public ContaBancaria(String titular, double saldoInicial) {
        this.titular = titular;
        this.saldo = saldoInicial;
    }

    public void depositar(double valor) {
        saldo += valor;
    }

    // Método final: não pode ser sobrescrito por subclasses
    public final void sacar(double valor) {
        if (valor <= saldo) {
            saldo -= valor;
        } else {
            System.out.println("Saldo insuficiente.");
        }
    }
}

// Classe final: não pode ser estendida
final class ContaPoupanca extends ContaBancaria {
    public ContaPoupanca(String titular, double saldoInicial) {
        super(titular, saldoInicial);
    }

    public void renderJuros(double taxa) {
        saldo += saldo * taxa;
    }
}

public class Main {
    public static void main(String[] args) {
        ContaPoupanca cp = new ContaPoupanca("Maria", 1000.0);
        cp.depositar(200.0);
        cp.sacar(100.0);
        cp.renderJuros(0.1); // 10% de juros sobre o saldo atual
        System.out.println("Saldo final: " + cp.saldo);
    }
}

Passo a passo

  1. A classe ContaBancaria tem os atributos titular e saldo, inicializados no construtor.
  2. O método depositar simplesmente soma o valor ao saldo.
  3. O método sacar é declarado final, impedindo que subclasses o modifiquem. Ele verifica se há saldo suficiente.
  4. A classe ContaPoupanca é final, então não pode ser estendida. Ela herda de ContaBancaria.
  5. O construtor de ContaPoupanca chama super(titular, saldoInicial).
  6. O método renderJuros aumenta o saldo com base na taxa fornecida.
  7. No main, criamos uma ContaPoupanca, depositamos, sacamos e rendemos juros, e imprimimos o saldo final.

Por que funciona

O uso de final em métodos e classes garante que certas partes do código não sejam alteradas por subclasses, promovendo segurança e consistência. A herança permite que ContaPoupanca reutilize a lógica de depósito e saque, enquanto adiciona funcionalidade específica.

Erros comuns

  • Tentar sobrescrever sacar em ContaPoupanca: o compilador gera erro porque o método é final.
  • Tentar estender ContaPoupanca: erro de compilação porque a classe é final.
  • Esquecer de chamar super no construtor: erro de compilação se a superclasse não tiver construtor padrão.

Outra forma de resolver

Poderia-se usar composição em vez de herança, mas para uma relação "é um" (ContaPoupanca é uma ContaBancaria), herança é apropriada. O uso de final é uma decisão de design para restringir a hierarquia.

Saída esperada

Saldo final: 1100.0