Resumo de Conceitos de POO em Java

Página de apoio para revisar, em ordem didática, os principais conceitos: classes, objetos, encapsulamento, relacionamentos, herança, classes abstratas, interfaces, sobrescrita e sobrecarga de métodos.

POO em Java Material de Aula Estudo Rápido

Fundamentos: classes, atributos, métodos e objetos

Ponto de partida da POO: modelar um tipo (classe), quais dados ele possui (atributos), quais ações realiza (métodos) e como criar instâncias concretas (objetos) em memória.

Quadro-resumo

Definições
Classe: molde Atributos: dados Métodos: ações Objeto: instância
  • Classe: modelo que descreve objetos com mesma estrutura e comportamento.
  • Atributos: variáveis que armazenam o estado de cada objeto.
  • Métodos: funções associadas à classe, responsáveis pelos comportamentos.
  • Objetos: “exemplares” concretos da classe em execução.

Exemplo em Java

Fundamentos
Classe simples e criação de objetos
class Jogador {
    String nome;      // atributo
    int idade;        // atributo
    double altura;    // atributo

    // método
    void apresentar() {
        System.out.println(
            "Jogador: " + nome +
            " (" + idade + " anos)"
        );
    }
}

public class AppFundamentos {
    public static void main(String[] args) {
        // objeto 1
        Jogador j1 = new Jogador();
        j1.nome = "Ana";
        j1.idade = 22;
        j1.altura = 1.72;
        j1.apresentar();

        // objeto 2
        Jogador j2 = new Jogador();
        j2.nome = "Carlos";
        j2.idade = 28;
        j2.altura = 1.85;
        j2.apresentar();
    }
}

Organização interna: encapsulamento, static e final

O foco é controlar como atributos e métodos podem ser acessados, além de trabalhar com membros de classe (static) e elementos imutáveis (final).

Quadro-resumo

Encapsulamento & Modificadores
Encapsulamento: esconder detalhes private / public static: da classe final: não muda
  • Encapsulamento: esconde detalhes internos e expõe apenas o necessário por métodos.
  • private: acesso restrito ao código da própria classe.
  • public: acesso liberado para outras classes.
  • static: membro pertence à classe, não ao objeto (compartilhado).
  • final: usado para constantes ou para impedir alterações.

Exemplo em Java

Encapsulamento
Encapsulamento, static e final
class ContaBancaria {
    private String titular;     // encapsulado
    private double saldo;       // encapsulado

    public static final double TAXA_SAQUE = 2.5; // constante

    public ContaBancaria(String titular) {
        this.titular = titular;
        this.saldo = 0;
    }

    public String getTitular() {
        return titular;
    }

    public double getSaldo() {
        return saldo;
    }

    public void depositar(double valor) {
        if (valor > 0) {
            saldo += valor;
        }
    }

    public void sacar(double valor) {
        double total = valor + TAXA_SAQUE;
        if (total <= saldo) {
            saldo -= total;
        }
    }
}

Relações entre classes: associação, agregação e composição

Relações estruturais entre classes ajudam a modelar sistemas mais próximos da realidade: “usa”, “tem-um” fraco (agregação) e “tem-um” forte (composição).

Quadro-resumo

Relacionamentos
Associação: usa Agregação: tem-um (fraco) Composição: tem-um (forte)
  • Associação: uma classe conhece/usa a outra, sem relação de parte-todo.
  • Agregação: relação parte-todo em que as partes podem existir sem o todo.
  • Composição: relação parte-todo forte, na qual as partes dependem do todo.

Exemplo em Java

Associação / Agregação / Composição
Sistema de torneio (exemplo simplificado)
// Associação: Arbitro usa Partida
class Arbitro {
    String nome;
    void apitar(Partida p) {
        System.out.println("Árbitro " + nome + " apitando " + p.descricao());
    }
}

// Agregação: Time possui Jogadores (podem existir sem o Time)
class Jogador {
    String nome;
}

class Time {
    String nome;
    java.util.List jogadores = new java.util.ArrayList<>();
}

// Composição: Partida cria e controla o Placar
class Placar {
    int pontosTimeA;
    int pontosTimeB;
}

class Partida {
    Time timeA;
    Time timeB;
    private Placar placar = new Placar(); // composição

    public Partida(Time a, Time b) {
        this.timeA = a;
        this.timeB = b;
    }

    String descricao() {
        return timeA.nome + " x " + timeB.nome;
    }
}

Reutilização: herança, classe abstrata e interfaces

Herança, classes abstratas e interfaces permitem reutilizar código e definir modelos genéricos para especialização, além de contratos que diferentes classes podem seguir.

Quadro-resumo

Generalização & Contratos
Herança: é-um Classe abstrata: modelo parcial Interface: contrato de métodos
  • Herança: subclasse herda atributos e métodos da superclasse.
  • Classe abstrata: não pode ser instanciada; pode ter métodos abstratos e concretos.
  • Interface: define apenas assinaturas de métodos; a implementação fica nas classes que a implementam.

Exemplo em Java

Herança & Abstração
Herança com classe abstrata e interface
// Interface: contrato para pontuar
interface Pontuavel {
    void pontuarTimeA(int pontos);
    void pontuarTimeB(int pontos);
}

// Classe abstrata: modelo para partidas
abstract class PartidaEsportiva {
    protected Time timeA;
    protected Time timeB;

    public PartidaEsportiva(Time a, Time b) {
        this.timeA = a;
        this.timeB = b;
    }

    public abstract void iniciar();
}

// Subclasse concreta que herda e implementa interface
class PartidaFutevolei extends PartidaEsportiva implements Pontuavel {
    private int pontosA = 0;
    private int pontosB = 0;

    public PartidaFutevolei(Time a, Time b) {
        super(a, b);
    }

    @Override
    public void iniciar() {
        System.out.println("Iniciando partida de futevôlei: " +
            timeA.nome + " x " + timeB.nome);
    }

    @Override
    public void pontuarTimeA(int pontos) {
        pontosA += pontos;
    }

    @Override
    public void pontuarTimeB(int pontos) {
        pontosB += pontos;
    }
}

Polimorfismo: sobrescrita e sobrecarga de métodos

Polimorfismo trata de como um mesmo nome de método pode ter comportamentos diferentes: redefinição em subclasses (sobrescrita) ou múltiplas assinaturas na mesma classe (sobrecarga).

Quadro-resumo

Polimorfismo
Sobrescrita: runtime Sobrecarga: compile-time
  • Sobrescrita (override): subclasse redefine método da superclasse com mesma assinatura.
  • Sobrecarga (overload): mesmos nomes, mas parâmetros diferentes na mesma classe.
  • Polimorfismo permite tratar objetos de subclasses via referência da superclasse.

Exemplo em Java

Override & Overload
Sobrescrita + sobrecarga em um contexto de frete
class Frete {
    // método base
    public double calcular(double peso, double distancia) {
        return peso * 1.0 + distancia * 0.5;
    }

    // sobrecarga: mesmo nome, parâmetros diferentes
    public double calcular(double peso) {
        return calcular(peso, 10); // distância padrão
    }
}

// sobrescrita: classe filha redefine o método
class FreteExpresso extends Frete {
    @Override
    public double calcular(double peso, double distancia) {
        // mais caro, mas mais rápido
        return peso * 1.5 + distancia * 0.8;
    }
}

public class AppPolimorfismo {
    public static void main(String[] args) {
        Frete freteNormal = new Frete();
        Frete freteExpresso = new FreteExpresso(); // polimorfismo

        System.out.println(freteNormal.calcular(5, 100));
        System.out.println(freteExpresso.calcular(5, 100)); // versão sobrescrita

        // Usando sobrecarga
        System.out.println(freteNormal.calcular(3)); // versão com 1 parâmetro
    }
}