Pular para o conteúdo

Orientação a Objetos em Java

Orientação a Objetos (OO) é um modelo de programação que organiza o código em objetos: “coisas” que têm dados (atributos) e comportamentos (métodos).

Uma boa analogia é um jogo de RPG:

  • Cada personagem tem dados: vida, mana, nome, nível.
  • Cada personagem tem ações: atacar, defender, usar magia.

Na OO:

  • A classe é como a ficha-modelo de personagem (define quais dados e ações existem).
  • O objeto é um personagem específico daquela ficha.

Uma classe define a estrutura de um tipo de objeto: seus atributos e métodos.

public class Cachorro {
// Atributos (dados)
String nome;
String cor;
double peso;
// Métodos (comportamentos)
void latir() {
System.out.println("Au au!");
}
void comer(double quantidadeRacao) {
this.peso += quantidadeRacao * 0.25;
}
}
  • Cachorro é a classe.
  • nome, cor, peso são atributos.
  • latir e comer são métodos.

Um objeto é uma instância concreta de uma classe:

public class Main {
public static void main(String[] args) {
Cachorro doguinho = new Cachorro(); // cria um objeto
doguinho.nome = "Paçoca";
doguinho.cor = "Caramelo";
doguinho.peso = 10.5;
doguinho.latir(); // chama método
doguinho.comer(0.2); // altera o estado interno (peso)
}
}

Analogia: a classe é o molde de biscoito; cada biscoito é um objeto gerado com esse molde.

Todas seguem essa ideia de “molde (classe) + instância (objeto)”.

Um construtor é um método especial chamado quando usamos new para criar o objeto. Ele:

  • Tem o mesmo nome da classe.
  • Não tem tipo de retorno (nem void).
  • Serve para inicializar o objeto.
public class Pessoa {
private String nome;
private int idade;
// Construtor “sem argumentos” (NoArgsConstructor)
public Pessoa() {
this.nome = "Desconhecido";
this.idade = 0;
}
// Construtor com argumentos (AllArgsConstructor)
public Pessoa(String nome, int idade) {
this.nome = nome;
this.idade = idade;
}
}

Uso:

Pessoa p1 = new Pessoa(); // usa o construtor vazio
Pessoa p2 = new Pessoa("Ana", 25); // usa o construtor com parâmetros

this é uma referência ao próprio objeto dentro do código da classe. Usamos, principalmente, para:

  • Diferenciar atributos da classe e parâmetros com o mesmo nome.
  • Encadear construtores (não obrigatório aqui).
public class Empregado {
private String nome;
private String sobrenome;
private double salarioMensal;
public Empregado(String nome, String sobrenome, double salarioMensal) {
// Parâmetros (nome, sobrenome, salarioMensal)
// Atributos (this.nome, this.sobrenome, this.salarioMensal)
this.nome = nome;
this.sobrenome = sobrenome;
this.salarioMensal = salarioMensal;
}
public void imprimirNomeCompleto() {
System.out.println(this.nome + " " + this.sobrenome);
}
}

Analogia: pense no this como “eu mesmo” para o objeto. Cada empregado tem seu próprio nome e, quando o código roda, this indica qual empregado está falando.

4. Encapsulamento, modificadores de acesso, getters e setters

Seção intitulada “4. Encapsulamento, modificadores de acesso, getters e setters”

Encapsulamento é a prática de esconder os detalhes internos de uma classe, expondo apenas o necessário. Em Java, usamos modificadores de acesso:

  • public: acessível de qualquer lugar.
  • private: acessível somente dentro da própria classe.
  • protected: acessível dentro do mesmo pacote e subclasses.

Exemplo ruim (sem encapsulamento):

public class ContaBancaria {
public double saldo; // Qualquer um pode mexer diretamente
}

Exemplo melhor:

public class ContaBancaria {
private double saldo;
public double getSaldo() {
return saldo;
}
public void depositar(double valor) {
if (valor > 0) {
this.saldo += valor;
}
}
public void sacar(double valor) {
if (valor > 0 && valor <= saldo) {
this.saldo -= valor;
}
}
}

Getters e setters são métodos públicos para ler e modificar atributos privados de forma controlada:

public class Fatura {
private String numero;
private String descricao;
private int quantidade;
private double precoPorItem;
// Getter
public String getNumero() {
return numero;
}
// Setter
public void setNumero(String numero) {
this.numero = numero;
}
// ...outros getters e setters...
}

Herança permite criar uma classe mais específica (subclasse) a partir de uma classe mais genérica (superclasse).

public class Funcionario {
protected String nome;
protected String codigo;
public void baterPonto() {
System.out.println("Funcionário bateu ponto.");
}
}
public class Professor extends Funcionario {
private String disciplina;
}
  • Professor herda (extends) Funcionario.
  • Professor tem nome, codigo, baterPonto() mais disciplina.

Uso:

Professor prof = new Professor();
prof.nome = "Ramon"; // herdado
prof.baterPonto(); // herdado

Analogia: Funcionario é “Animal”, Professor é “Cachorro”. Cachorro é um tipo de Animal, mas tem características específicas.

Isso permite código compartilhado na classe base e comportamentos especializados nas subclasses.

Polimorfismo é a capacidade de um mesmo nome de método representar comportamentos diferentes.

Mesma classe, mesmo nome de método, assinaturas diferentes (parâmetros diferentes).

public class Calculadora {
public int somar(int a, int b) {
return a + b;
}
public int somar(int a, int b, int c) {
return a + b + c;
}
}

Subclasse redefine o comportamento de um método da superclasse, mantendo a mesma assinatura.

public class BasePorto {
public void atracarBarco(Barco barco) {
System.out.println("Barco atracado.");
}
}
public class PortoPequeno extends BasePorto {
@Override
public void atracarBarco(Barco barco) {
if (barco.getTamanho() <= 10) {
System.out.println(barco.getNome() + " atracado no porto pequeno");
} else {
System.out.println("Barco grande demais para porto pequeno");
}
}
}

Analogia: um mesmo comando “atacar” pode significar coisas diferentes para um mago e um guerreiro. O nome é o mesmo, a implementação muda.

Uma classe abstrata:

  • Não pode ser instanciada diretamente.
  • Pode ter métodos concretos e métodos abstratos.
  • Serve como modelo para subclasses.
public abstract class Biocombustivel {
protected float quilogramas;
public Biocombustivel(float quilogramas) {
this.quilogramas = quilogramas;
}
public abstract float processar();
}

Subclasse:

public class CanaAcucar extends Biocombustivel {
public CanaAcucar(float quilogramas) {
super(quilogramas);
}
@Override
public float processar() {
return quilogramas * 3.5f;
}
}

Uma interface define um conjunto de métodos que as classes devem implementar. Não contém implementação concreta (em versões modernas de Java pode conter métodos default, mas em disciplinas introdutórias geralmente usamos apenas métodos abstratos).

public interface PlataformaSocial {
void compartilharPostagem(Postagem postagem);
void compartilharImagem(Postagem postagem);
void compartilharVideo(Postagem postagem);
}

Implementação:

public class MyBook implements PlataformaSocial {
@Override
public void compartilharPostagem(Postagem postagem) {
System.out.println("Postagem compartilhada no MyBook: " + postagem.getTitulo());
}
@Override
public void compartilharImagem(Postagem postagem) { /* ... */ }
@Override
public void compartilharVideo(Postagem postagem) { /* ... */ }
}

Analogia: uma interface é como um contrato: qualquer classe que assine o contrato se compromete a fornecer aquelas operações.

Toda classe em Java herda, direta ou indiretamente, de java.lang.Object. Isso significa que qualquer objeto Java tem, por exemplo:

  • toString()
  • equals(Object o)
  • hashCode()
Fatura fatura = new Fatura(/* ... */);
System.out.println(fatura.toString()); // representação textual

Na prática, você pode sobreescrever toString() em suas classes de modelo (Fatura, Empregado, Data, Personagem, etc.) para facilitar depuração e impressão de relatórios.