← → navega · N notas · F tela cheia
Módulo 2 de 5

Encapsulamento e
Membros de Classe

Proteger o estado do objeto com private, expor o que é seguro com getters e setters, e conhecer static, sobrecarga, equals, hashCode e toString.

Programação Orientada a Objetos em Java  ·  Docente: Profa. Andréa Barboza Proto Sardi
Abertura. Este módulo resolve a "ferida" deixada no Módulo 1: atributos abertos. Tudo gira em torno de proteger e dar acesso controlado ao estado. A classe Aluno evolui de fato aqui.
Módulo 2 · Abertura

Objetivos de aprendizagem

Ao final, você será capaz de:

🔒Proteger

Usar private e expor acesso por getters/setters com validação.

🌐Compartilhar

Diferenciar membros de instância de membros static (da classe).

🔀Sobrecarregar

Criar métodos de mesmo nome com assinaturas diferentes.

🟰Comparar & descrever

Sobrescrever equals, hashCode e toString.

Objetivos. Quatro competências. A primeira é o coração do módulo (encapsulamento); as demais são "membros e contratos" da classe. Tudo será aplicado na classe Aluno e numa classe Pessoa.
Retomada · Situação-problema

O perigo do estado aberto

Main.java
Conta c = new Conta();
c.saldo = -9999;   // e ninguém impede!
💥
o problema
Com atributos abertos, qualquer ponto do código pode colocar o objeto em um estado inválido.

🎯A solução

Esconder os atributos sensíveis (private) e só permitir mudanças por métodos que validam. Isso é encapsulamento.

Gancho. Retome literalmente o saldo=-9999 do Módulo 1. A pergunta-motriz: "como impedir que o objeto fique inválido?". A resposta é o tema do dia. Não entregue a solução ainda; deixe a turma sentir a dor.
Conceito 1

Encapsulamento

Proteger as partes sensíveis do objeto e expor apenas o que é seguro, por meio de métodos.

🔒Estado oculto

Os atributos viram private — invisíveis de fora da classe.

🚪Interface exposta

Métodos public são a porta de entrada controlada para ler e alterar o estado.

🏧
analogia
Um caixa eletrônico: você não mete a mão no cofre (private). Usa botões — sacar, depositar (public) — que seguem regras.
Encapsulamento. Cofre × botões é a melhor analogia. A classe decide como seu estado pode mudar. Isso reduz bugs e facilita manutenção: a regra mora num único lugar (o método), não espalhada pelo código.
Conceito 2

Modificadores de visibilidade

ModificadorMesma classeMesmo pacoteGlobal (qualquer pacote)
public (+)✓ visível✓ visível✓ visível
protected (#)✓ visível✓ visível⚠ só por herança
default (~)✓ visível✓ visível✗ invisível
private (-)✓ visível✗ invisível✗ invisível
boa prática
Atributos majoritariamente private (protegidos); acesso via métodos public (getters/setters).
Visibilidade. Os símbolos +/-/#/~ são os mesmos do UML. protected e default ganham importância em herança e pacotes (Módulos 4 e 5). Por ora, a regra de ouro: atributo private, método public.
Conceito 3

Getters e setters

A ponte controlada entre o mundo externo e o estado private.

Pessoa.java
private String nome;

public String getNome() {        // getter: LÊ
    return nome;
}
public void setNome(String nome) { // setter: ESCREVE
    this.nome = nome;
}
🔑
convenção
get + atributo para ler · set + atributo para escrever. É um padrão universal em Java.
Get/Set. O setter parece "só repassar" agora — mas é o lugar onde colocaremos validação no próximo slide. A IDE gera get/set automaticamente (Alt+Insert), mas o aluno deve entender o que cada um faz. Note o this (Módulo 1) ressurgindo no setter.
Conceito 4 · invariantes

O poder do setter: validar

Conta.java
private double saldo;

public void setSaldo(double saldo) {
    if (saldo < 0) {
        System.out.println("Saldo inválido!");
        return;            // barra o estado ruim
    }
    this.saldo = saldo;
}
🛡️
invariante
Agora saldo < 0 é impossível por fora. A regra vive em um único ponto.

Resolvemos o saldo = -9999 do Módulo 1: o atributo é private e o setter recusa valores inválidos.

Validação. Aqui o encapsulamento "paga". O setter é o guardião do invariante. Mostre que sem private isso não adiantaria (alguém ainda mexeria direto). É o fechamento do arco aberto no Módulo 1.
Projeto · Aluno evolui

Aluno: somaNotas protegido

Aluno.java
class Aluno {
    String nome;
    private double somaNotas;  // oculto

    public void lerNota(double nota) {
        somaNotas += nota;       // só aqui muda
    }
    public double getSomaNotas() {
        return somaNotas;
    }
}
Main.java
Aluno a = new Aluno();
a.lerNota(6.0);
a.lerNota(6.0);
a.lerNota(6.0);

// a.somaNotas = 20;  ✗ NÃO compila
System.out.println(a.getSomaNotas());
// → 18.0
Aluno encapsulado. Direto dos exercícios da disciplina. Antes aluno1.somanotas = 20 funcionava; agora não compila — a única forma de somar é lerNota(). O total só cresce de forma controlada. Mostre a linha comentada que daria erro.
Comparação

Antes × depois

Antes (aberto)

aluno1.somaNotas = 20;
Qualquer um sobrescreve o total a qualquer momento. Estado frágil.

Depois (encapsulado)

aluno1.lerNota(6.0);
O total só muda somando notas válidas. Estado confiável.

?
Verificação
Por que tornar somaNotas private muda o comportamento permitido na classe Main?
Antes/depois. Resposta: private remove a permissão de acesso direto fora da classe; a Main passa a depender da interface pública (lerNota/getSomaNotas). É exatamente o exercício "torne somanotas private" da disciplina.
Projeto · regra de negócio

Frequência e limite de faltas

Aluno.java
private final int frequenciaMax = 15;
private int frequencia;

public void lancarFrequencia(int faltas) { frequencia += faltas; }

public void verificarQtdFaltas() {
    if (frequencia == frequenciaMax) System.out.println("Atingiu o limite!");
    else if (frequencia > frequenciaMax) System.out.println("Ultrapassou o limite!");
    else System.out.println("Faltas: " + frequencia);
}
🔐
final = constante
private final torna frequenciaMax uma constante: definida uma vez, nunca alterada.
Frequência. Direto do exercício. A regra de negócio (máximo 15 faltas) fica encapsulada na própria classe. Introduza final como "constante". A cada lançamento, o aluno verifica se passou do limite — comportamento centralizado e protegido.
Conceito 5

Membros static: da classe, não do objeto

Um atributo static é compartilhado por todas as instâncias — existe uma única cópia, na classe.

Aluno.java
static int contaAluno = 0;   // 1 cópia para TODOS

public Aluno() {       // construtor
    contaAluno++;          // cada novo aluno incrementa
}
🌐
instância × static
Atributo de instância: um por objeto (ex.: nome). Atributo static: um para a classe inteira (ex.: contaAluno).
static (atributo). Exercício "quantos alunos cadastrados". Cada objeto tem seu nome (instância), mas o contador é único e vive na classe (static). O construtor incrementa a cada new. Desenhe: 3 alunos, 3 nomes, 1 contador compartilhado.
Conceito 6

Métodos static: chamados pela classe

Aluno.java
static public void qtdAlunos() {
    System.out.println(
        "Cadastrados: " + contaAluno);
}
Main.java
Aluno a1 = new Aluno();
Aluno a2 = new Aluno();

Aluno.qtdAlunos();  // pela CLASSE!
// → Cadastrados: 2
📞
como chamar
Método static é invocado pela classe (Aluno.qtdAlunos()), não por um objeto. É por isso que o main é static.
static (método). Agora "fecha" o mistério do main do Módulo 0: ele é static porque a JVM o chama sem ter um objeto ainda. Método static não acessa atributos de instância (não há "this"). Mostre a chamada Aluno.qtdAlunos() — sem new.
Conceito 7

Sobrecarga (overloading)

Vários métodos com o mesmo nome, diferenciados pela assinatura (tipo/quantidade de parâmetros).

Calculadora.java
int soma(int a, int b)            { return a + b; }
double soma(double a, double b)   { return a + b; }
int soma(int a, int b, int c)     { return a + b + c; }
🎯
quem decide é o compilador
Pela assinatura da chamada, o Java escolhe a versão certa em tempo de compilação.
?
Atividade
Mudar só o tipo de retorno (mesmos parâmetros) conta como sobrecarga?
Sobrecarga. Resposta da atividade: NÃO — a assinatura considera nome + parâmetros, não o retorno. Distinga já de "sobrescrita" (Módulo 4): sobrecarga é mesma classe, assinaturas diferentes; sobrescrita é subclasse, mesma assinatura.
Conceito 8 · igualdade

== compara o quê?

Main.java
Pessoa p1 = new Pessoa("Maria", 23);
Pessoa p2 = new Pessoa("Maria", 23);

System.out.println(p1 == p2);
// → false  (são objetos diferentes!)
⚠️
cuidado clássico
== compara referências (mesmo endereço no heap), não o conteúdo. Dois objetos "iguais" têm endereços diferentes.
==. Liga direto a referências (Módulo 1). p1 e p2 têm os mesmos dados, mas são objetos distintos → == dá false. Para comparar conteúdo, precisamos de equals — próximo slide. Erro frequentíssimo em provas.
Conceito 9

Sobrescrevendo equals( )

Pessoa.java
@Override
public boolean equals(Object o) {
    Pessoa p = (Pessoa) o;
    return idade == p.idade
        && nome.equals(p.nome);
}
🟰
igualdade lógica
Agora p1.equals(p2) compara conteúdo (nome + idade) e retorna true.

@Override avisa o compilador que estamos substituindo um método herdado de Object.

equals. Toda classe herda equals de Object (que compara referência, igual ao ==). Sobrescrevendo, definimos o que "iguais" significa no nosso domínio. @Override é introduzido aqui como anotação de segurança — formalizamos a sobrescrita no Módulo 4. Use String.equals para comparar os nomes (não ==!).
Conceito 10

hashCode( ) e o contrato

Pessoa.java
@Override
public int hashCode() {
    return Objects.hash(nome, idade);
}
🤝
a regra de ouro
Se sobrescreveu equals, sobrescreva também hashCode. Objetos iguais devem ter o mesmo hash.

Objects.hash(...) gera um código a partir dos mesmos campos usados no equals. É o que coleções como HashSet e HashMap usam para localizar objetos.

hashCode. O "contrato equals/hashCode": iguais por equals ⇒ mesmo hashCode. Quebrar isso causa bugs sutis em HashSet/HashMap (Módulo 3). Use Objects.hash com os MESMOS campos do equals. A IDE gera os dois juntos por isso.
Conceito 11 · retomada do M1

toString( ), agora formalmente

Pessoa.java
@Override
public String toString() {
    return "Nome: " + nome
         + " | Idade: " + idade;
}
🔁
o ciclo se completa
No Módulo 1 usamos toString pela utilidade. Agora entendemos: é uma sobrescrita de um método de Object.

equals, hashCode e toString são os três métodos de Object que quase toda classe sobrescreve.

toString (formal). Promessa do Módulo 1 cumprida: toString é herdado de Object e sobrescrito com @Override. Agrupe os três (equals/hashCode/toString) como "o trio de Object". Conecte ao polimorfismo que virá: println chama o toString certo em tempo de execução.
Erros frequentes

Onde se tropeça

🟰Usar == para conteúdo

Comparar objetos com == em vez de equals. Quase sempre dá false.

🤝equals sem hashCode

Sobrescrever um e esquecer o outro → bugs em HashSet/HashMap.

🔓Getter que vaza

Private no atributo, mas um getter devolve referência mutável e dá acesso por fora.

🌐static onde devia ser instância

Tornar static um dado que é de cada objeto → todos compartilham sem querer.

Erros. O par == vs equals e o contrato equals/hashCode são campeões de prova. O "getter que vaza" é mais avançado — mencione de leve. O static indevido aparece quando o aluno usa static para "resolver" erros de compilação sem entender.
Prática guiada

Aluno completo (encapsulado)

Aluno.java (resumo)
class Aluno {
    String nome;
    private double somaNotas;
    private final int frequenciaMax = 15;
    private int frequencia;
    static int contaAluno = 0;

    public Aluno() { contaAluno++; }
    public void lerNota(double n) { somaNotas += n; }
    public double getSomaNotas() { return somaNotas; }
    public void lancarFrequencia(int f) { frequencia += f; }
    // + verificarQtdFaltas() e static qtdAlunos()
}
Prática guiada. Monte a classe Aluno completa com a turma, juntando tudo: encapsulamento (somaNotas, frequencia), constante (frequenciaMax), static (contaAluno) e construtor. É a versão consolidada dos exercícios. Rode com 2 alunos e chame qtdAlunos().
Exercício autônomo

Sua vez: classe Pessoa

📋Requisitos

• Atributos private: nome (String) e idade (int).
• Construtor que recebe nome e idade (use this).
• Getters e setters para ambos.
• Sobrescreva equals, hashCode e toString.
• Na Main: crie duas Pessoas "Maria, 23" e mostre que ==false mas equalstrue.

!
Entrega
Saída esperada: false (pelo ==) e true (pelo equals).
Exercício autônomo. Tempo: 15 min. É a classe Pessoa dos exercícios, que consolida encapsulamento + o trio de Object. Reaproveitaremos Pessoa no Módulo 4 (herança). Recolha as soluções.
Revisão · verificação

Revisão relâmpago

private esconde; getters/setters dão acesso controlado.
Setter valida → garante invariantes.
static = membro da classe (1 cópia para todos).
== referência · equals conteúdo · sempre com hashCode.
?
Questão 1
Para que serve um setter além de atribuir?
?
Questão 2
Por que main é static?
?
Questão 3
Qual o "contrato" entre equals e hashCode?
Revisão. Respostas: (1) validar e centralizar regras (invariantes). (2) é chamado pela JVM sem objeto existir → membro da classe. (3) objetos iguais por equals devem ter o mesmo hashCode. Ticket de saída.
Síntese do Módulo 2

O que levamos deste módulo

🔒Proteção

Estado private + acesso por métodos = objetos sempre válidos.

🌐Classe vs instância

static pertence à classe; o resto pertence a cada objeto.

🟰O trio de Object

equals, hashCode e toString sob medida.

➡️
próximo módulo
Relacionamentos e Coleções — um Aluno raramente está sozinho. Vamos guardar muitos objetos em listas e relacioná-los.
Síntese. Três pilares: proteção, classe×instância, trio de Object. Ponte para o Módulo 3: precisamos de uma turma de alunos — coleções. Encerramento: "nossos objetos agora são seguros; vamos organizá-los em grupos".
módulos
Nota de apresentação para a docente