Em concursos para Analista Judiciário – TI, Programação Orientada a Objetos (OOP) costuma ser cobrada tanto em conceitos (definições e diferenças) quanto em leitura de código (identificar princípios e efeitos de design). O foco aqui é entender os pilares e aplicar em entidades típicas do Judiciário, evitando confusões comuns em questões.
Classe e objeto: o que são e como diferenciar em prova
Conceito
Classe é um “molde” (tipo) que define atributos (dados) e métodos (comportamentos). Objeto é uma instância concreta criada a partir da classe, com estado próprio.
- Classe: definição (ex.:
Processo). - Objeto: ocorrência (ex.: o processo de número 0001234-56.2025.8.01.0001).
Confusões frequentes em questões
- Classe ≠ objeto: classe não “guarda dados de um caso real” por si; quem guarda é o objeto (instância).
- Tipo ≠ instância: “variável do tipo Processo” pode estar
null(sem instância) em linguagens que permitem referência nula. - Atributo de classe (estático) ≠ atributo de instância: estático é compartilhado por todas as instâncias; instância é individual.
Exemplo de modelagem (Processo, Parte, Usuário, Permissão)
// Exemplo conceitual (estilo Java/C#), focado em leitura de prova: atributos + métodos + invariantes simples
class Processo {
String numero;
String classeJudicial; // ex.: "Ação de Cobrança"
List<Parte> partes;
Usuario responsavel;
void adicionarParte(Parte p) { /* ... */ }
boolean podeSerAcessadoPor(Usuario u) { /* ... */ return false; }
}
class Parte {
String nome;
String tipo; // ex.: "Autor", "Réu", "Terceiro"
}
class Usuario {
String login;
Set<Permissao> permissoes;
boolean temPermissao(Permissao p) { /* ... */ return false; }
}
class Permissao {
String codigo; // ex.: "PROCESSO_VISUALIZAR"
}Encapsulamento: proteger invariantes e reduzir dependências
Conceito
Encapsulamento é esconder detalhes internos e expor uma interface controlada de uso. Em prova, aparece como: uso de modificadores de acesso (private/protected/public), getters/setters com validação, e métodos que preservam regras do domínio (invariantes).
Passo a passo prático: encapsular o número do processo
- 1) Identifique um dado que não pode ficar “livre” para qualquer alteração (ex.: número do processo).
- 2) Torne o atributo privado.
- 3) Exponha método de leitura e, se fizer sentido, método de alteração com validação (ou não exponha alteração).
- 4) Centralize a regra no método, evitando validação duplicada fora da classe.
class Processo {
private String numero;
public Processo(String numero) {
if (!validarNumero(numero)) {
throw new IllegalArgumentException("Número inválido");
}
this.numero = numero;
}
public String getNumero() {
return numero;
}
// Sem setNumero: evita que o número mude após criado (invariante)
private boolean validarNumero(String n) {
// validação simplificada para fins didáticos
return n != null && n.length() >= 10;
}
}Diferenças conceituais cobradas
- Encapsulamento ≠ ocultação total: você expõe operações necessárias, mas controla como o estado muda.
- Getter/setter não é sinônimo de encapsular: se setters permitem qualquer valor sem regra, você só “escondeu” o campo, mas não protegeu invariantes.
- Imutabilidade (quando aplicável) reforça encapsulamento: menos pontos de alteração, menos bugs.
Herança: generalização e especialização (e quando evitar)
Conceito
Herança modela relação “é-um” (is-a): uma classe derivada herda atributos/métodos de uma base e pode especializar comportamento. Em concursos, é comum cobrar: sobrescrita (override), visibilidade (protected), e substituição por polimorfismo.
Exemplo: tipos de usuário
class Usuario {
protected String login;
public boolean podeAssinar() { return false; }
}
class UsuarioServidor extends Usuario {
@Override
public boolean podeAssinar() { return true; }
}
class UsuarioAdvogado extends Usuario {
@Override
public boolean podeAssinar() { return true; }
}Confusões frequentes
- Herança ≠ composição: herança é “é-um”; composição é “tem-um”.
- Reuso por herança pode aumentar acoplamento: mudanças na base impactam derivadas.
- Herança múltipla: nem toda linguagem suporta; quando não suporta, interfaces costumam suprir parte da necessidade.
Polimorfismo: mesma interface, comportamentos diferentes
Conceito
Polimorfismo permite tratar objetos de classes diferentes por um tipo comum (classe base ou interface), chamando o mesmo método e obtendo comportamentos distintos (despacho dinâmico). Em prova, aparece em trechos onde uma variável do tipo base aponta para objeto derivado.
Continue em nosso aplicativo
Você poderá ouvir o audiobook com a tela desligada, ganhar gratuitamente o certificado deste curso e ainda ter acesso a outros 5.000 cursos online gratuitos.
ou continue lendo abaixo...Baixar o aplicativo
Leitura de código: identificar polimorfismo e sobrescrita
Usuario u = new UsuarioServidor();
boolean pode = u.podeAssinar();- O que a variável “é” (tipo estático):
Usuario. - O que o objeto “é” (tipo dinâmico):
UsuarioServidor. - Método executado: o
podeAssinar()sobrescrito emUsuarioServidor.
Confusões frequentes
- Polimorfismo ≠ sobrecarga: sobrecarga (overload) é escolher método por assinatura em tempo de compilação; polimorfismo (override) é escolher implementação em tempo de execução.
- Cast: converter referência não muda o objeto; só muda a “visão” do tipo, e pode falhar se incompatível.
Interfaces: contrato de comportamento e desacoplamento
Conceito
Interface define um contrato (assinaturas) que classes implementam. Ajuda a reduzir acoplamento: o código depende do contrato, não de uma classe concreta. Em prova, é comum cobrar: “programar para interface”, implementação múltipla e substituição de implementações.
Exemplo: autorização por política
interface PoliticaDeAcesso {
boolean podeVisualizar(Processo p, Usuario u);
}
class PoliticaPadrao implements PoliticaDeAcesso {
public boolean podeVisualizar(Processo p, Usuario u) {
return u.temPermissao(new Permissao("PROCESSO_VISUALIZAR"));
}
}
class ServicoProcesso {
private final PoliticaDeAcesso politica;
ServicoProcesso(PoliticaDeAcesso politica) {
this.politica = politica;
}
public void abrir(Processo p, Usuario u) {
if (!politica.podeVisualizar(p, u)) {
throw new SecurityException("Acesso negado");
}
// ...
}
}Passo a passo prático: “programar para interface”
- 1) Identifique um ponto que varia (ex.: regra de acesso).
- 2) Extraia um contrato (interface) com o método necessário.
- 3) Crie implementações (ex.: política padrão, política restrita).
- 4) Injete a interface no serviço (construtor/parâmetro), evitando dependência direta da implementação.
Diferenças cobradas
- Interface ≠ classe abstrata: interface é contrato; classe abstrata pode trazer estado e implementação parcial (depende da linguagem), além de restringir herança a uma única base em muitas linguagens.
- Implementar interface não implica herdar código; implica cumprir assinaturas.
Composição: “tem-um” e modelagem de entidades do domínio
Conceito
Composição é construir objetos a partir de outros objetos, representando relação “tem-um” (has-a). Em design, costuma ser preferida ao reuso por herança quando o objetivo é montar comportamentos/estruturas sem criar hierarquias rígidas.
Exemplo: Processo tem Partes e pode ter Responsável
class Processo {
private List<Parte> partes = new ArrayList<>();
private Usuario responsavel;
public void definirResponsavel(Usuario u) {
this.responsavel = u;
}
public void adicionarParte(Parte p) {
if (p == null) throw new IllegalArgumentException();
partes.add(p);
}
}Confusões frequentes
- Composição ≠ agregação: em UML, agregação é relação mais “fraca” (ciclo de vida independente); composição é mais “forte” (parte depende do todo). Em questões, o examinador pode usar a ideia de ciclo de vida para diferenciar.
- Composição ≠ herança: “Processo tem Partes” não significa que Processo “é uma” Parte.
Coesão e acoplamento: boas práticas cobradas indiretamente
Conceito
Coesão mede o quanto as responsabilidades de uma classe estão relacionadas entre si. Acoplamento mede o quanto uma classe depende de detalhes de outra. Boa prática: alta coesão e baixo acoplamento.
Exemplo de baixa coesão (sinal de alerta em prova)
class Processo {
// Mistura domínio + persistência + segurança + formatação
void salvarNoBanco() { /* ... */ }
boolean podeAcessar(Usuario u) { /* ... */ return false; }
String gerarRelatorioPDF() { /* ... */ return "..."; }
}Em leitura de prova, isso sugere violação de separação de responsabilidades: a classe está fazendo “coisas demais”.
Exemplo com melhor coesão e menor acoplamento
class Processo {
private String numero;
// regras do domínio do processo
}
interface RepositorioDeProcessos {
void salvar(Processo p);
}
interface GeradorDeRelatorio {
byte[] gerar(Processo p);
}
class ServicoDeProcessos {
private final RepositorioDeProcessos repo;
private final GeradorDeRelatorio relatorios;
ServicoDeProcessos(RepositorioDeProcessos repo, GeradorDeRelatorio relatorios) {
this.repo = repo;
this.relatorios = relatorios;
}
}- Coesão:
Processofoca no domínio; serviços focam em casos de uso. - Acoplamento: serviços dependem de interfaces, não de classes concretas.
Diferenças conceituais que mais caem (mapa rápido)
- Classe vs Objeto: definição vs instância.
- Encapsulamento vs Abstração: encapsulamento controla acesso e protege invariantes; abstração seleciona o que é relevante e omite detalhes.
- Herança vs Composição: “é-um” vs “tem-um”.
- Polimorfismo (override) vs Sobrecarga (overload): escolha em tempo de execução vs escolha por assinatura.
- Interface vs Classe abstrata: contrato vs base com possível implementação parcial/estado (dependendo da linguagem).
- Associação vs Agregação vs Composição: vínculo genérico vs vínculo fraco vs vínculo forte (ciclo de vida).
Exercícios de leitura e interpretação (estilo concurso)
Exercício 1: identificar encapsulamento e invariantes
class Usuario {
private String login;
private Set<Permissao> permissoes = new HashSet<>();
public void conceder(Permissao p) {
if (p == null) throw new IllegalArgumentException();
permissoes.add(p);
}
public boolean temPermissao(String codigo) {
for (Permissao p : permissoes) {
if (p.getCodigo().equals(codigo)) return true;
}
return false;
}
}- a) O que está encapsulado? Identifique membros privados e como o acesso é controlado.
- b) Qual invariante simples é protegido em
conceder? - c) Por que não expor diretamente
permissoescomo público reduz riscos?
Exercício 2: herança, polimorfismo e método executado
class Parte {
public String tipo() { return "GENERICA"; }
}
class ParteAutor extends Parte {
@Override
public String tipo() { return "AUTOR"; }
}
Parte p = new ParteAutor();
String t = p.tipo();- a) Há herança? Justifique pela relação entre classes.
- b) Há polimorfismo? Explique usando tipo estático e dinâmico.
- c) Qual valor vai para
te por quê?
Exercício 3: interface e desacoplamento
interface Auditoria {
void registrar(String evento);
}
class AuditoriaArquivo implements Auditoria {
public void registrar(String evento) { /* grava em arquivo */ }
}
class ServicoPermissao {
private final Auditoria auditoria;
ServicoPermissao(Auditoria auditoria) { this.auditoria = auditoria; }
void conceder(Usuario u, Permissao p) {
u.conceder(p);
auditoria.registrar("Concedida: " + p.getCodigo());
}
}- a) Onde está o “programar para interface”?
- b) Se trocar
AuditoriaArquivoporAuditoriaBanco, o que muda noServicoPermissao? - c) Isso reduz acoplamento? Explique.
Exercício 4: composição vs herança (pegadinha)
class Processo {
private Usuario responsavel;
}
class UsuarioResponsavel extends Usuario {
private Processo processo;
}- a) Qual modelagem faz mais sentido para “responsável pelo processo”: composição no
Processoou herança emUsuarioResponsavel? Justifique usando “é-um” vs “tem-um”. - b) Que problema de acoplamento pode surgir ao criar muitos “subtipos por papel” (ex.: UsuarioResponsavel, UsuarioDistribuidor, UsuarioAssinante)?
Exercício 5: coesão e acoplamento em trecho de código
class ProcessoController {
public void abrirTela(Processo p) { /* UI */ }
public void salvar(Processo p) { /* SQL direto aqui */ }
public boolean validarAcesso(Usuario u) { /* regra de permissão */ return true; }
}- a) A coesão está alta ou baixa? Por quê?
- b) Cite duas responsabilidades misturadas indevidamente.
- c) Reescreva (apenas em termos de classes/nomes) uma separação melhor: quais classes/serviços você criaria?