Усі підходи до копіювання об’єктів у Java мають серйозні недоліки:
Клон
- Метод clone () захищений, тому ви не можете викликати його безпосередньо, доки відповідний клас не замінить його загальнодоступним методом.
- clone () не викликає конструктор. Будь-який конструктор. Він виділить пам’ять, призначить внутрішнє
class
поле (яке можна прочитати через getClass()
) та скопіює поля оригіналу.
Щоб отримати додаткові відомості про clone (), див. Пункт 11 книги Джошуа Блоха " Ефективна Java, друге видання "
Серіалізувати
Серіалізувати ще гірше; він має багато недоліків, clone()
а потім і деякі. У Джошуа є ціла глава з чотирма пунктами лише на цю тему.
Моє рішення
Моє рішення - додати новий інтерфейс до моїх проектів:
public interface Copyable<T> {
T copy ();
T createForCopy ();
void copyTo (T dest);
}
Код виглядає так:
class Demo implements Copyable<Demo> {
public Demo copy () {
Demo copy = createForCopy ();
copyTo (copy);
return copy;
}
public Demo createForCopy () {
return new Demo ();
}
public void copyTo (Demo dest)
super.copyTo (dest);
...copy fields of Demo here...
}
}
На жаль, я повинен скопіювати цей код до всіх своїх об'єктів, але це завжди один і той же код, тому я можу використовувати шаблон редактора Eclipse. Переваги:
- Я можу вирішити, який конструктор викликати і як ініціалізувати яке поле.
- Ініціалізація відбувається у детермінованому порядку (від кореневого класу до класу екземпляра)
- Я можу повторно використовувати існуючі об'єкти та перезаписувати їх
- Тип безпечний
- Самотні залишаються одноосібниками
Для стандартних типів Java (наприклад, колекції тощо) я використовую утилітний клас, який може їх копіювати. Методи мають прапори та зворотні виклики, тому я можу контролювати, наскільки глибокою повинна бути копія.