A clonagem é um paradigma de programação básico. O fato de que o Java pode ter implementado mal em muitos aspectos não diminui a necessidade de clonagem. E é fácil implementar a clonagem que funcionará da maneira que você quiser, superficial, profunda, mista, o que for. Você pode até usar o nome clone para a função e não implementar Cloneable, se desejar.
Suponha que eu tenha classes A, B e C, onde B e C são derivados de A. Se eu tiver uma lista de objetos do tipo A como esta:
ArrayList<A> list1;
Agora, essa lista pode conter objetos do tipo A, B ou C. Você não sabe de que tipo são os objetos. Portanto, você não pode copiar a lista desta forma:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(new A(a));
}
Se o objeto for realmente do tipo B ou C, você não obterá a cópia correta. E se A for abstrato? Agora, algumas pessoas sugeriram isto:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
if(a instanceof A) {
list2.add(new A(a));
} else if(a instanceof B) {
list2.add(new B(a));
} else if(a instanceof C) {
list2.add(new C(a));
}
}
Esta é uma ideia muito, muito ruim. E se você adicionar um novo tipo derivado? E se B ou C estiverem em outro pacote e você não tiver acesso a eles nesta aula?
O que você gostaria de fazer é:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(a.clone());
}
Muitas pessoas indicaram por que a implementação básica do Java do clone é problemática. Mas, é facilmente superado desta forma:
Na classe A:
public A clone() {
return new A(this);
}
Na classe B:
@Override
public B clone() {
return new B(this);
}
Na classe C:
@Override
public C clone() {
return new C(this):
}
Não estou implementando Cloneable, apenas usando o mesmo nome de função. Se você não gosta disso, dê outro nome.