Pular para o conteúdo

Tópicos Especiais em Java

1. A classe Object e o tipo mais genérico de todos

Seção intitulada “1. A classe Object e o tipo mais genérico de todos”

Em Java, todas as classes herdam direta ou indiretamente de java.lang.Object. Isso significa que qualquer objeto tem alguns métodos em comum, como:

  • toString()
  • equals(Object o)
  • hashCode()
  • getClass()

Retorna uma representação textual do objeto. Por padrão, é algo como NomeDaClasse@hashCode.

Empregado emp = new Empregado("Ana", "Silva", 3000.0);
System.out.println(emp.toString()); // saída padrão, pouco amigável

É comum sobrescrever toString() para facilitar debug e impressão de objetos:

public class Empregado {
// ...atributos, construtor...
@Override
public String toString() {
return nome + " " + sobrenome + " - R$ " + salarioMensal;
}
}

Usados para comparar objetos e para que coleções como HashSet e HashMap funcionem corretamente.

Empregado e1 = new Empregado("Ana", "Silva", 3000.0);
Empregado e2 = new Empregado("Ana", "Silva", 3000.0);
System.out.println(e1 == e2); // false (endereços diferentes)
System.out.println(e1.equals(e2)); // depende da implementação de equals()

Como todas as classes herdam de Object, você pode ter estruturas de dados que guardam “qualquer coisa”:

Object[] vetor = new Object[3];
vetor[0] = "Hello";
vetor[1] = 123;
vetor[2] = new Empregado("Ana", "Silva", 3000.0);

No entanto, em código moderno, preferimos usar Generics (List<Empregado>, List<String>, etc.) para ter segurança de tipos em tempo de compilação.

Construtores são métodos especiais usados para criar e inicializar objetos. Eles têm o mesmo nome da classe e não possuem tipo de retorno.

Para classes de domínio (como Fatura, Data, Filme, Biocombustivel, Personagem), é comum:

  • Ter um construtor que receba os atributos necessários.
  • Validar dados dentro do construtor, se fizer sentido.
public class Data {
private int dia;
private int mes;
private int ano;
public Data(int dia, int mes, int ano) {
// Você pode chamar um método de validação aqui
if (!validaData(dia, mes, ano)) {
throw new IllegalArgumentException("Data inválida");
}
this.dia = dia;
this.mes = mes;
this.ano = ano;
}
// ...método validaData, getters, displayData()...
}

Você pode ter mais de um construtor, desde que as assinaturas sejam diferentes:

public class Biocombustivel {
protected float quilogramas;
public Biocombustivel() {
this.quilogramas = 1000f; // valor padrão
}
public Biocombustivel(float quilogramas) {
this.quilogramas = quilogramas;
}
}

Collections são estruturas de dados prontas da biblioteca padrão para guardar múltiplos objetos de forma organizada.

As principais interfaces e implementações que você precisa conhecer para os exercícios:

  • List – lista ordenada, aceita duplicatas.
  • Set – conjunto que não permite duplicatas.
  • Map – pares chave-valor.
  • Implementações comuns: ArrayList, LinkedList, HashSet, HashMap.

Uma List é similar a um “vetor dinâmico”: pode crescer e diminuir.

import java.util.ArrayList;
import java.util.List;
List<Personagem> inimigos = new ArrayList<>();
inimigos.add(new Personagem("Orc", 100, 10));
inimigos.add(new Personagem("Goblin", 50, 5));
inimigos.add(new Personagem("Lobo", 75, 15));

Operações comuns:

for (Personagem inimigo : inimigos) {
inimigo.atacar(jogador);
}
Personagem primeiro = inimigos.get(0);
int tamanho = inimigos.size();
boolean listaVazia = inimigos.isEmpty();

Um Set não aceita elementos duplicados. Útil, por exemplo, para garantir que assentos vendidos ("A1", "B3") não sejam repetidos.

import java.util.HashSet;
import java.util.Set;
Set<String> assentosOcupados = new HashSet<>();
assentosOcupados.add("A1"); // true
assentosOcupados.add("A1"); // false (já existe)

Um Map armazena pares (chave, valor). Exemplo: nome da música como chave, objeto Musica como valor.

import java.util.HashMap;
import java.util.Map;
Map<String, Musica> musicasDisponiveis = new HashMap<>();
musicasDisponiveis.put("Hino do Real Paulista", new Musica("Hino do Real Paulista", "Banda X"));
Musica m = musicasDisponiveis.get("Hino do Real Paulista");
if (m != null) {
// música existe
} else {
// música não encontrada
}

Embora a lista peça apenas uma Collection, saber de Map ajuda em buscas mais eficientes.

Exceções representam erros ou situações anormais que podem ocorrer durante a execução do programa.

  • Checked exceptions: precisam ser tratadas ou declaradas com throws em tempo de compilação (ex.: IOException, FileNotFoundException).
  • Unchecked exceptions: são subclasses de RuntimeException. Não são obrigatórias de tratar (ex.: NullPointerException, ArithmeticException).

No contexto das listas, você vai:

  • Criar exceções customizadas (como GeradorCheioException).
  • Usar try-catch para tratar problemas de negócio (assento ocupado, idade insuficiente, música não encontrada, incompatibilidade de tipo de postagem).

Você pode lançar uma exceção explicitamente quando alguma regra é violada:

public double dividir(double dividendo, double divisor) {
if (divisor == 0) {
throw new ArithmeticException("Impossível dividir por zero!");
}
return dividendo / divisor;
}

Para capturar e tratar uma exceção:

try {
biogerador.carregar(biocombustivel);
} catch (GeradorCheioException e) {
System.out.println("O gerador está cheio. Processo interrompido.");
}

Exemplo de múltiplos casos de erro no cinema:

try {
cinema.venderIngresso(cliente, nomeFilme, assento);
System.out.println("Ingresso vendido com sucesso!");
} catch (AssentoIndisponivelException e) {
System.out.println("O ingresso não pode ser vendido pois seu assento não está mais disponível!");
} catch (IdadeInsuficienteException e) {
System.out.println("O ingresso não pode ser vendido pois sua idade não permite!");
}

Se um método pode lançar uma checked exception, você pode:

  • Tratar internamente com try-catch, ou
  • Propagar para quem chama usando throws.
public void leArquivo(String caminho) throws FileNotFoundException {
File file = new File(caminho);
// ...código que pode lançar FileNotFoundException...
}

Em projetos maiores, é comum criar uma camada de serviço que lança exceções específicas, e uma camada de apresentação que trata e exibe mensagens amigáveis.

Você pode criar suas próprias classes de exceção, geralmente herdando de Exception (checked) ou RuntimeException (unchecked).

public class GeradorCheioException extends Exception {
public GeradorCheioException(String mensagem) {
super(mensagem);
}
}

Uso:

public void carregar(Biocombustivel b) throws GeradorCheioException {
if (this.cargaAtual >= this.cargaMaxima) {
throw new GeradorCheioException("Biogerador já está cheio!");
}
// ...restante do processamento...
}

Essas exceções deixam o código mais legível e a regra de negócio mais clara.