Клонирование - это базовая парадигма программирования. Тот факт, что Java, возможно, плохо реализовал это во многих отношениях, нисколько не уменьшает необходимость клонирования. И легко реализовать клонирование, которое будет работать так, как вы хотите, мелкое, глубокое, смешанное, что угодно. Вы даже можете использовать имя clone для функции и не реализовывать 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, просто использую то же имя функции. Если вам это не нравится, назовите что-нибудь другое.