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
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
}
private para atributos e acesse-os através de métodos getter/setter.
Getters e Setters
Por que Getters/Setters são Necessários
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
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
}
}
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
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 + "}";
}
}
Encapsulamento na Prática
Exemplo: Conta Bancária
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
}
}
Exemplo: Validação de Preço de Produto
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 + ")";
}
}
Regras de Nomenclatura Getter/Setter
| Tipo de Atributo | Getter | Setter |
|---|---|---|
boolean married |
isMarried() |
setMarried() |
String name |
getName() |
setName() |
int age |
getAge() |
setAge() |
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
- Encapsulamento oculta implementação interna e protege dados
- Use private para atributos, acesse através de getters/setters
- Quatro modificadores de acesso: public, protected, padrão, private
- Convenções JavaBean: atributos privados, getters/setters, construtor sem argumentos
📝 Exercícios
- Classe Student: Defina uma classe Student com atributos encapsulados, valide score entre 0-100
- Classe Date: Defina uma classe de data com ano/mês/dia encapsulados, forneça validação de data
- 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.



