← → navega · N notas · F tela cheia
Módulo 3 de 5

Relacionamentos e
Coleções

Como objetos se relacionam (associação e composição) e como guardar e percorrer muitos objetos com arrays e com o Collections Framework.

Programação Orientada a Objetos em Java  ·  Docente: Profa. Andréa Barboza Proto Sardi
Abertura. Saímos de "um objeto" para "muitos objetos colaborando". Dois temas: relacionamentos (como objetos se conectam) e coleções (como armazená-los). O projeto ganha uma turma de alunos.
Módulo 3 · Abertura

Objetivos de aprendizagem

🔗Relacionar

Distinguir associação de composição entre objetos.

📦Armazenar

Usar arrays e entender sua principal limitação.

📋Coletar

Trabalhar com List/ArrayList — o vetor dinâmico.

🔁Percorrer

Iterar coleções com for e com for-each, usando generics.

Objetivos. Dois blocos: relacionamentos e coleções. A motivação prática (uma turma) costura tudo. Generics aparece como o "tipo seguro" das coleções.
Retomada · Situação-problema

Um aluno não é uma turma

Já sabemos criar e proteger um Aluno. Mas uma escola tem centenas. Criar aluno1, aluno2, ... aluno300 é inviável.

💥
o problema
Precisamos de uma estrutura que guarde vários objetos e que cresça conforme a necessidade.

🎯Dois caminhos

O array (tamanho fixo, simples) e a coleção (tamanho dinâmico, poderosa). Veremos os dois.

Gancho. Ridicularize de leve a ideia de 300 variáveis. A necessidade de "guardar muitos" motiva arrays e, depois, coleções. Antes disso, vemos como os objetos se relacionam entre si.
Conceito 1

Associação: objetos que se conhecem

Um objeto guarda uma referência a outro como atributo. É uma relação do tipo "usa / tem um".

Livro.java
public class Livro {
    String titulo;
    Autor autor;   // associação: Livro TEM UM Autor
}
🔗
a chave
O tipo de um atributo pode ser outra classe. Assim os objetos formam uma rede.
Associação. Retoma a colaboração do Módulo 1 (transferePara recebia uma Conta). Aqui o relacionamento é estrutural: o Livro tem um Autor como atributo. Outros exemplos: Aluno tem Curso; Pedido tem Cliente.
Conceito 2

Composição: relação parte-todo

Uma forma forte de associação: a parte não existe sem o todo. É um "é feito de".

🚗Carro é feito de Motor

O Motor é criado dentro do Carro. Destruiu o carro, foi-se o motor.

🏫Associação (mais fraca)

Um Professor dá aula numa Escola, mas existe independente dela.

🧩
teste prático
"Se eu destruir o todo, a parte deixa de fazer sentido?" Sim → composição. Não → associação.
Composição. Diferença de "vínculo de vida". Composição: parte criada e destruída com o todo (Carro/Motor, Pedido/ItemDePedido). Associação: vidas independentes. Em UML, composição é o losango preenchido. Não exagere no rigor — a intuição parte-todo basta agora.
Conceito 3 · vetor estático

Array: a primeira forma de guardar vários

sintaxe
Tipo[] nome = new Tipo[3];

int[] numero = new int[3];
numero[0] = 10;
numero[1] = 20;
numero[2] = 30;
10[0] 20[1] 30[2]
Posições contíguas, acessadas por índice (começa em 0).
Array. Sintaxe Tipo[] x = new Tipo[n]. Índice começa em 0; o último é n-1. Atenção ao ArrayIndexOutOfBounds. O array é a base; coleções vêm a seguir para superar suas limitações.
Vetor estático · uso

Percorrendo com for

Main.java
Integer[] numero = new Integer[3];
numero[0] = 1; numero[1] = 1; numero[2] = 1;

for (int i = 0; i < 3; i++) {
    System.out.println(numero[i]);
}
📏
tamanho do array
numero.length dá o tamanho. O laço vai de 0 até length - 1.
?
Verificação
O que acontece se você acessar numero[3] num array de tamanho 3?
Percorrer. Resposta: ArrayIndexOutOfBoundsException — índices válidos são 0..2. Use .length em vez de "3" fixo para evitar bugs. Esse for clássico será simplificado pelo for-each adiante.
Situação-problema

A limitação do array: tamanho fixo

Ao criar new Tipo[3], o tamanho está travado. E se chegar um 4º aluno?

🔒Não cresce

Para adicionar mais, você teria que criar um array maior e copiar tudo na mão.

🛠️Trabalhoso

Remover do meio, buscar, reordenar — tudo manual. Muito código repetitivo.

💡
a saída
O Java já resolveu isso por nós: o Collections Framework, com estruturas que crescem sozinhas.
Limitação. "Arrays são trabalhosos" (fonte da disciplina). Tamanho fixo + operações manuais. Esse é o gancho perfeito para Collections: "não reinvente a roda — use a lista que o Java oferece".
Conceito 4

Collections Framework

Um conjunto de classes e interfaces do pacote java.util que representa estruturas de dados prontas e robustas.

📚Não reinvente a roda

Listas, conjuntos, mapas, filas — testados e otimizados, prontos para usar.

📋Começamos pela List

Uma lista permite elementos duplicados e mantém a ordem de inserção.

📦
import
Para usar: import java.util.ArrayList; (ou java.util.List) no topo do arquivo.
Collections. Reside em java.util desde o Java 2 (1.2). É a biblioteca padrão de estruturas de dados. Comece pela List por ser a mais intuitiva (parecida com array, mas dinâmica). Mencione import sem aprofundar pacotes (Módulo 5).
Conceito 5

List e a ArrayList

📜List (a interface)

Especifica o que uma lista deve saber fazer: adicionar, remover, buscar, contar.

ArrayList (a implementação)

A mais usada. Usa um array interno que cresce sozinho. Rápida para buscar.

⚖️
ArrayList × LinkedList
ArrayList é mais rápida na busca; LinkedList, na inserção/remoção nas pontas.
List. Distinção interface × implementação (prepara o Módulo 4). List é o "contrato"; ArrayList é uma forma de cumpri-lo. Para o curso, ArrayList resolve quase tudo. A comparação com LinkedList é cultura geral por ora.
Vetor dinâmico · uso

Criar, adicionar, ler

Main.java
import java.util.ArrayList;

ArrayList<String> nomes = new ArrayList<>();
nomes.add("maria");
nomes.add("joão");

System.out.println(nomes.size());  // 2
System.out.println(nomes.get(0)); // maria
MétodoFaz
add(x)adiciona ao fim
get(i)lê pelo índice
size()quantos há
remove(i)remove
ArrayList básico. Note o <> vazio na criação (inferência de tipo). add cresce a lista automaticamente — sem tamanho fixo! get/size substituem o índice e o .length do array. Mostre ao vivo adicionando um 3º nome sem "criar array maior".
Vetor dinâmico · operações

Buscar, conferir, remover

Main.java
nomes.indexOf("joão");     // → 1  (posição)
nomes.contains("maria");   // → true
nomes.add(0, "ana");      // insere no início
nomes.remove("joão");      // remove pelo valor
🧰
tudo pronto
Buscar, verificar presença, inserir em posição e remover — sem você escrever a lógica.
?
Atividade
Qual a diferença entre remove(0) e remove("ana")?
Operações. Resposta: remove(int) remove por índice; remove(Object) remove pela primeira ocorrência do valor — exemplo de sobrecarga (Módulo 2!). indexOf usa equals internamente — conecte com o trio de Object. contains devolve boolean.
Conceito 6

Generics: listas com tipo

O <Tipo> diz à lista o que ela guarda. O compilador garante: nada de tipo errado entra.

ArrayList<Aluno>

Só aceita Aluno. Ao tirar com get, já vem como Aluno — sem conversão manual.

⚠️ArrayList sem tipo

Aceita qualquer coisa. Você perde a segurança e precisa fazer casts arriscados.

🛡️
segurança de tipos
Generics transforma erros de tipo em erros de compilação (cedo), não de execução (tarde).
Generics. ArrayList<Pessoa> dos exercícios. Vantagem dupla: o compilador barra tipos errados e o get já devolve o tipo certo. Conecte com primitivos×wrappers do Módulo 1 (generics só aceita objetos → use Integer, não int).
Conceito 7

Percorrendo com for-each

🔢for tradicional

verboso
for (int i=0; i<lista.size(); i++){
  System.out.println(lista.get(i));
}

for-each

limpo
for (Aluno a : turma) {
  System.out.println(a.getNome());
}
📖
leia assim
"para cada Aluno a dentro de turma". Sem índices, sem erro de fronteira.
for-each. Sintaxe: for(Tipo elemento : colecao). Mais legível e sem off-by-one. Use quando só precisar ler cada elemento (não para remover durante a iteração). É o jeito idiomático de varrer coleções.
Projeto · Gestão Acadêmica

Uma turma de Alunos

Main.java
Aluno a1 = new Aluno(); a1.nome = "Ana";
Aluno a2 = new Aluno(); a2.nome = "Caio";

ArrayList<Aluno> turma = new ArrayList<>();
turma.add(a1);
turma.add(a2);

for (Aluno a : turma) {
    System.out.println(a.nome);   // Ana / Caio
}
🎓
o sistema cresce
A turma agora comporta quantos alunos quiser — e percorrê-la é uma linha de for-each.
Turma. Marco do projeto evolutivo: de objetos isolados para uma coleção de objetos do nosso domínio. Junta tudo: classe Aluno (M1/M2), ArrayList<Aluno> (generics), for-each. A partir daqui dá para calcular média da turma, contar reprovados, etc.
Aplicação

Funciona com qualquer objeto

Main.java
Conta c1 = new Conta(); c1.deposita(100);
Conta c2 = new Conta(); c2.deposita(200);

ArrayList<Conta> contas = new ArrayList<>();
contas.add(c1);
contas.add(c2);

for (Conta c : contas) c.exibeSaldo();
♻️
reuso
A mesma técnica serve para Alunos, Contas, Pessoas, Produtos... troca-se apenas o tipo entre < >.
Generalização. Mostra que coleções são agnósticas ao domínio — é o poder dos generics. Lista de Contas Correntes é exemplo das fontes. Reforce: o conhecimento se transfere para qualquer entidade.
Erros frequentes

Onde se tropeça

📏Index out of bounds

Acessar get(size()) ou array[length] — o último índice é tamanho − 1.

📦Esquecer o import

Usar ArrayList sem import java.util.ArrayList; → não compila.

🏷️Lista sem generics

Esquecer o <Tipo> e precisar de casts perigosos depois.

🔁Remover durante for-each

Alterar a lista enquanto a percorre com for-each → exceção de concorrência.

Erros. Os dois primeiros são imediatos para iniciantes. "Remover no for-each" é mais sutil (ConcurrentModificationException) — mencione e diga que se resolve com Iterator ou laço por índice reverso. Generics esquecido gera warnings que viram bugs.
Prática guiada

Média da turma

🎯Construir juntos

1. Crie 3 objetos Aluno com notas (use lerNota).
2. Adicione-os a uma ArrayList<Aluno> turma.
3. Com for-each, some as médias e imprima a média geral da turma.

🧮
dica
Use turma.size() como divisor — o código se adapta a qualquer quantidade de alunos.
Prática guiada. Integra M1+M2+M3: objetos, encapsulamento e coleção. O uso de size() como divisor mostra a vantagem da lista dinâmica (não precisa saber a quantidade de antemão). Faça ao vivo, peça previsões da saída.
Exercício autônomo

Sua vez: catálogo de Livros

📋Requisitos

• Classe Autor (nome) e classe Livro com associação a um Autor.
• Crie 3 livros (com autores) e guarde numa ArrayList<Livro>.
• Com for-each, imprima título + nome do autor de cada livro.
• Use contains ou indexOf para localizar um livro específico.

!
Entrega
Lista impressa + a posição de um livro buscado.
Exercício autônomo. Tempo: 20 min. Combina associação (Livro–Autor) com coleção. Reforça que o tipo de um atributo pode ser outra classe. Recolha; serve de base para herança (Livro/Autor poderiam compartilhar Pessoa, no Módulo 4).
Revisão · verificação

Revisão relâmpago

Associação = "tem um"; composição = parte-todo.
Array = tamanho fixo; ArrayList = cresce sozinho.
Generics <Tipo> garante segurança de tipos.
for-each percorre sem índices.
?
Questão 1
Qual a principal limitação do array que a ArrayList resolve?
?
Questão 2
Por que <Aluno> é melhor que uma lista sem tipo?
?
Questão 3
Quando usar composição em vez de associação?
Revisão. Respostas: (1) tamanho fixo → ArrayList cresce dinamicamente. (2) segurança de tipos em compilação + sem casts. (3) quando a parte não existe sem o todo. Ticket de saída.
Síntese do Módulo 3

O que levamos deste módulo

🔗Relacionamentos

Objetos se conectam por associação e composição.

📋Coleções

ArrayList + generics guardam muitos objetos com segurança.

🔁Iteração

for-each percorre tudo de forma limpa.

➡️
próximo módulo
Herança e Polimorfismo — Aluno e Professor são, no fundo, Pessoas. Vamos reaproveitar código com hierarquias.
Síntese. Relacionamentos + coleções + iteração. Ponte: percebemos repetição entre Aluno e Professor (ambos têm nome/idade) — herança elimina isso. Encerramento: "já agrupamos objetos; agora vamos organizá-los em famílias".
módulos
Nota de apresentação para a docente