Клонирование - это базовая парадигма программирования. Тот факт, что Java, возможно, реализовал его во многих отношениях, вовсе не уменьшает необходимость клонирования. И легко реализовать клонирование, которое будет работать так, как вы хотите, чтобы оно работало, мелкое, глубокое, смешанное, что угодно. Вы даже можете использовать имя клон для функции и не реализовывать Cloneable, если хотите.
Предположим, у меня есть классы A, B и C, где B и C получены из A. Если у меня есть список объектов типа A, подобный этому:
ArrayList<A> list1;
Теперь этот список может содержать объекты типа A, B или C. Вы не знаете, к какому типу относятся эти объекты. Таким образом, вы не можете скопировать список следующим образом:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(new A(a));
}
Если объект на самом деле имеет тип B или C, вы не получите правильную копию. И что, если А абстрактно? Теперь некоторые люди предложили это:
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));
}
}
Это очень, очень плохая идея. Что если вы добавите новый производный тип? Что если B или C находятся в другом пакете, и у вас нет доступа к ним в этом классе?
Что бы вы хотели сделать, это:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(a.clone());
}
Многие люди указали, почему базовая реализация клона на Java проблематична. Но это легко преодолеть следующим образом:
В классе А:
public A clone() {
return new A(this);
}
В классе B:
@Override
public B clone() {
return new B(this);
}
В классе C:
@Override
public C clone() {
return new C(this):
}
Я не реализую Cloneable, просто использую то же имя функции. Если вам это не нравится, назовите это как-нибудь еще.