Encapsulamento

Encapsulamento é uma das características centrais da OOP. Esta lição cobre como proteger dados de objetos.

O que é Encapsulamento

Encapsulamento agrupa dados (atributos) e métodos que operam nesses dados juntos, ocultando detalhes de implementação interna.

Benefícios do Encapsulamento

Benefício Descrição
Proteção de dados Impede acesso e modificação externa direta
Flexibilidade Pode adicionar lógica de validação nos setters
Manutenibilidade Alterações internas não afetam chamadas externas

Modificadores de Acesso

Java tem quatro modificadores de acesso que controlam a visibilidade de classes, atributos e métodos.

Modificador Mesma Classe Mesmo Pacote Subclasse Pacote Diferente
public
protected
Padrão (sem modificador)
private

Exemplo: Modificadores de Acesso

JAVA
public class Person {
    public String name;      // Público, acessível em qualquer lugar
    protected int age;       // Protegido, acessível no mesmo pacote e subclasses
    String address;          // Padrão, acessível no mesmo pacote
    private double salary;   // Privado, acessível apenas nesta classe
}
▶ Experimente
💡 Recomendação: Use private para atributos e acesse-os através de métodos getter/setter.

Getters e Setters

Por que Getters/Setters são Necessários

JAVA
public class Person {
    private String name;
    private int age;
    
    // Getter
    public String getName() {
        return name;
    }
    
    // Setter
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        // Adicionar lógica de validação no setter
        if (age >= 0 && age <= 150) {
            this.age = age;
        } else {
            System.out.println("Idade inválida");
        }
    }
}

Exemplo: Usando Getters/Setters

JAVA
public class PersonTest {
    public static void main(String[] args) {
        Person p = new Person();
        
        // Definir valores via setters
        p.setName("Alice");
        p.setAge(25);
        
        // Obter valores via getters
        System.out.println("Nome: " + p.getName());
        System.out.println("Idade: " + p.getAge());
        
        // Validação no setter
        p.setAge(-5);  // Saída: Idade inválida
    }
}
▶ Experimente

Convenções JavaBean

JavaBean é um tipo especial de classe Java que segue convenções específicas.

Regras JavaBean

Regra Descrição
Atributos privados Modificados com private
Fornecer getters/setters getXxx() e setXxx()
Construtor sem argumentos Obrigatório
Implementar Serializable Opcional, para serialização

Exemplo: JavaBean Padrão

JAVA
import java.io.Serializable;

public class User implements Serializable {
    // Atributos privados
    private String username;
    private String password;
    private int age;
    
    // Construtor sem argumentos
    public User() {}
    
    // Construtor parametrizado
    public User(String username, String password, int age) {
        this.username = username;
        this.password = password;
        this.age = age;
    }
    
    // Getters/Setters
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    public String getPassword() {
        return password;
    }
    
    public void setPassword(String password) {
        if (password.length() >= 6) {
            this.password = password;
        } else {
            System.out.println("A senha deve ter pelo menos 6 caracteres");
        }
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        if (age >= 0 && age <= 150) {
            this.age = age;
        } else {
            System.out.println("Idade inválida");
        }
    }
    
    @Override
    public String toString() {
        return "User{username='" + username + "', age=" + age + "}";
    }
}
▶ Experimente

Encapsulamento na Prática

Exemplo: Conta Bancária

JAVA
public class BankAccount {
    private String accountId;
    private double balance;
    private String owner;
    
    public BankAccount(String accountId, String owner) {
        this.accountId = accountId;
        this.owner = owner;
        this.balance = 0;
    }
    
    // Depositar
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("Depositado: " + amount + ", Saldo: " + balance);
        } else {
            System.out.println("Valor do depósito deve ser maior que 0");
        }
    }
    
    // Sacar
    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.println("Sacado: " + amount + ", Saldo: " + balance);
        } else if (amount > balance) {
            System.out.println("Saldo insuficiente");
        } else {
            System.out.println("Valor do saque deve ser maior que 0");
        }
    }
    
    // Verificar saldo
    public double getBalance() {
        return balance;
    }
    
    public void showInfo() {
        System.out.println("Conta: " + accountId + ", Proprietário: " + owner + ", Saldo: " + balance);
    }
    
    public static void main(String[] args) {
        BankAccount account = new BankAccount("10001", "Alice");
        account.showInfo();  // Conta: 10001, Proprietário: Alice, Saldo: 0.0
        
        account.deposit(1000);  // Depositado: 1000.0, Saldo: 1000.0
        account.deposit(500);   // Depositado: 500.0, Saldo: 1500.0
        account.withdraw(200);  // Sacado: 200.0, Saldo: 1300.0
        account.withdraw(2000); // Saldo insuficiente
    }
}
▶ Experimente

Exemplo: Validação de Preço de Produto

JAVA
public class Product {
    private String name;
    private double price;
    private int stock;
    
    public Product(String name, double price, int stock) {
        this.name = name;
        setPrice(price);
        setStock(stock);
    }
    
    public String getName() {
        return name;
    }
    
    public double getPrice() {
        return price;
    }
    
    public void setPrice(double price) {
        if (price >= 0) {
            this.price = price;
        } else {
            System.out.println("O preço não pode ser negativo");
        }
    }
    
    public int getStock() {
        return stock;
    }
    
    public void setStock(int stock) {
        if (stock >= 0) {
            this.stock = stock;
        } else {
            System.out.println("O estoque não pode ser negativo");
        }
    }
    
    // Calcular preço total
    public double getTotalPrice(int quantity) {
        if (quantity > 0 && quantity <= stock) {
            return price * quantity;
        } else {
            System.out.println("Quantidade inválida");
            return 0;
        }
    }
    
    @Override
    public String toString() {
        return name + " - $" + price + " (Estoque: " + stock + ")";
    }
}
▶ Experimente

Regras de Nomenclatura Getter/Setter

Tipo de Atributo Getter Setter
boolean married isMarried() setMarried()
String name getName() setName()
int age getAge() setAge()
⚠️ Caso especial: Para tipos boolean, o getter usa o prefixo is, não get.

❓ Perguntas Frequentes

P: Por que não usar apenas atributos públicos? R: Atributos públicos não fornecem controle de acesso. Setters podem adicionar lógica de validação para proteger a integridade dos dados.

P: Todos os atributos precisam de getters/setters? R: Não necessariamente. Atributos somente leitura precisam apenas de getters. Atributos somente escrita precisam apenas de setters.

P: Qual é a diferença entre construtores e setters? R: Construtores são chamados ao criar objetos. Setters modificam atributos após o objeto ser criado.

📖 Resumo

📝 Exercícios

  1. Classe Student: Defina uma classe Student com atributos encapsulados, valide score entre 0-100
  2. Classe Date: Defina uma classe de data com ano/mês/dia encapsulados, forneça validação de data
  3. Melhoria BankAccount: Adicione validação de senha, exija senha para saques

Próxima Lição

Na próxima lição, aprenderemos sobre Herança — um mecanismo importante para reutilização de código.

100%