) atletas.clone();
}
}
```
---
# Solução 2: retornar uma cópia da lista
Nessa situação, o cliente de `Equipe` pode até modificar a lista retornada por `getAtletas()`, mas isso é irrelevante porque a lista original será preservada.
object programa {
}
object equipe {
}
object atletas {
}
object copiaDeAtletas {
}
programa --> equipe
programa --> copiaDeAtletas
equipe --> atletas
---
# Cópia rasa e cópia profunda
- Ao chamar `atletas.clone()`, estamos criando uma **cópia rasa** (*shallow copy*) da lista: a nova lista contém referência para os objetos originais da classe `Atleta`
- Assim, estamos escapando referências para os atletas da equipe -- mas isso não é um problema, pois atletas são **imutáveis**
- Uma **cópia profunda** (*deep copy*) de uma lista é aquela na qual não somente é criada uma cópia da lista, mas também a nova lista referencia cópias dos elementos da lista original
- Se nossa lista contivesse objetos mutáveis, precisaríamos criar uma cópia profunda para evitar que os clientes modificassem esses objetos
---
# Cópia rasa e cópia profunda
Cópia rasa:
object lista {
}
object a {
}
object b {
}
object c {
}
object copiaLista {
}
lista --> a
lista --> b
lista --> c
copiaLista --> a
copiaLista --> b
copiaLista --> c
Cópia profunda:
object lista {
}
object a {
}
object b {
}
object c {
}
object copiaA {
}
object copiaB {
}
object copiaC {
}
object copiaLista {
}
lista --> a
lista --> b
lista --> c
copiaLista --> copiaA
copiaLista --> copiaB
copiaLista --> copiaC
---
# Cópia rasa e cópia profunda
- Na **cópia profunda**, criamos uma cópia dos elementos da lista
- Mas note que a cópia dos elementos pode ser uma cópia rasa ou profunda
- Assim, ao falar em cópia profunda, faz sentido falar em níveis de profundidade
Considere o seguinte cenário:
object lista {
}
object a {
}
object b {
}
object x {
}
object y {
}
lista --> a
lista --> b
a --> x
b --> y
---
# Cópia rasa e cópia profunda
Cópia profunda de `lista` com um nível de profundidade:
object lista {
}
object copiaLista {
}
object a {
}
object b {
}
object copiaA {
}
object copiaB {
}
object x {
}
object y {
}
lista --> a
lista --> b
copiaLista --> copiaA
copiaLista --> copiaB
a --> x
b --> y
copiaA --> x
copiaB --> y
---
# Cópia rasa e cópia profunda
Cópia profunda de `lista` com dois níveis de profundidade:
object lista {
}
object copiaLista {
}
object a {
}
object b {
}
object copiaA {
}
object copiaB {
}
object x {
}
object y {
}
object copiaX {
}
object copiaY {
}
lista --> a
lista --> b
copiaLista --> copiaA
copiaLista --> copiaB
a --> x
b --> y
copiaA --> copiaX
copiaB --> copiaY
---
# Solução 3: coleções não-modificáveis
- Java possui um método estático `Collections.unmodifiableList(l)`, que retorna um *wrapper* (embrulho) para a lista `l`, que lança exceção sempre que chamamos um método que deveria modificar a lista (ex.: `add()`, `remove()`):
- Assim, nossa solução poderia ser assim:
```java
public class Equipe {
public List getAtletas() {
return Collection.unmodifiableList(atletas.clone());
}
}
```
- A vantagem dessa solução é que ele não cria uma cópia da lista (o que pode ser custoso)
- Da mesma forma que na solução anterior, essa solução só atende porque os objetos do tipo `Atleta` são imutáveis
---
# Solução 3: coleções não-modificáveis
- Como listas não-modificáveis funcionam? O método `Collections.unmodifiableList(l)` retorna um objeto de uma outra classe (chamaremos de `UnmodifiableList`), que é implementada mais ou menos assim (isso é apenas uma simplificação!):
```java
public class UnmodifiableList {
private List listaOriginal;
// ...
public int size() {
return listaOriginal.size()
}
public void add(elemento) {
* throw new UnsupportedOperationException();
}
// ...
}
```
- A lista não modificável possui uma referência para a lista original
- Ela delega os métodos de leitura para a lista original
- Nos métodos de modificação da lista, ela chama uma exceção
- Assim, garantimos que quem possuir uma referência para a lista não-modificável conseguirá ler a lista original, mas não conseguirá alterá-la
</div>