Concetio de Clonagem
Em Java, frequentemente necessitamos criar uma réplica independente de um objeto existente, onde modificações na cópia não afetam o original. A clonagem oferece uma solução eficiente para esse cenário. Todos os herdam de java.lang.Object, que contém o método clone(), responsável por gerar uma nova instância com valores idênticos ao objeto atual.
Implementando o Método clone()
Para habilitar a clonagem, a classe deve implementar a interface Cloneable e sobrescrever clone() com acesso público:
class ExemploClonagem implements Cloneable {
int valor;
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
Pontos essenciais:
Cloneableatua como marcador, permitindo queObject.clone()execute- Chamada
super.clone()utiliza o mecanismo nativo eficiente da JVM - Sem
Cloneable,clone()lançaCloneNotSupportedException
Cópia Superficial vs Profunda
Cópia Superficial: Duplica apenas o objeto base, mantendo referências aos mesmos objetos internos.
Cópia Profunda: Clona recursivamente todo o grafo de objetos, criando novas instâncias para todos os componentes.
Exemplo de Cópia Superficial
class Professor implements Cloneable {
String nome;
int idade;
// Método clone padrão (superficial)
}
class Aluno implements Cloneable {
String nome;
Professor tutor;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone(); // Clona apenas Aluno, mantendo referência ao mesmo Professor
}
}
Exemplo de Cópia Profunda
class Aluno implements Cloneable {
String nome;
Professor tutor;
@Override
public Object clone() throws CloneNotSupportedException {
Aluno copia = (Aluno) super.clone();
copia.tutor = (Professor) tutor.clone(); // Clona o objeto interno
return copia;
}
}
Cópia Profunda via Serialização
Alternativa para objetos complexos implementando Serializable:
class Estudante implements Serializable {
Professor orientador;
public Object deepClone() throws IOException, ClassNotFoundException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ObjectOutputStream saida = new ObjectOutputStream(buffer);
saida.writeObject(this);
ByteArrayInputStream entradaBytes = new ByteArrayInputStream(buffer.toByteArray());
ObjectInputStream entrada = new ObjectInputStream(entradaBytes);
return entrada.readObject();
}
}
Observação: Esta abordagem é mais custosa computacionalmente devido ao processamento de I/O.