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.
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.
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();
}
}
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).
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 estruturais entre classes ajudam a modelar sistemas mais próximos da realidade: “usa”, “tem-um” fraco (agregação) e “tem-um” forte (composição).
// 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;
}
}
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.
// 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 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).
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
}
}