Для чего вы использовали Object.clone()?
Недавно коллега спросил меня, как глубоко клонировать карту, и я понял, что, вероятно, никогда не использовал метод clone(), который меня беспокоит.
Каковы наиболее распространенные сценарии, которые вы обнаружили для клонирования объекта?
Ответы
Ответ 1
Я предполагаю, что вы ссылаетесь на Object.clone()
в Java. Если да, имейте в виду, что Object.clone()
имеет некоторые серьезные проблемы, и его использование в большинстве случаев не рекомендуется. Для получения полного ответа см. Пункт 11, от "Эффективная Java" от Джошуа Блоха. Я считаю, что вы можете безопасно использовать Object.clone()
для массивов примитивных типов, но помимо этого вам нужно быть разумным в правильном использовании и переопределении клона. Вероятно, вам лучше определить конструктор копирования или статический метод factory, который явно клонирует объект в соответствии с вашей семантикой.
Ответ 2
Чаще всего, когда мне приходится возвращать изменчивый объект вызывающему, который меня волнует, вызывающий может сбрасывать, часто в нитке-недружелюбном. Списки и дата - это те, которые я делаю для большинства. Если вызывающий объект, скорее всего, захочет перебирать список, и у меня есть потоки, возможно, обновляющие его, безопаснее возвращать клон или его копию.
Собственно, это вызывает что-то, что мне нужно будет открыть еще один вопрос: копировать конструкторы или клонировать? Когда я делал С++, мы ВСЕГДА делали конструктор копирования и реализовали клон с ним, но FindBugs не нравится, если вы реализуете свой клон с помощью конструктора копирования.
Ответ 3
Когда мне нужно сделать дубликат чего-то, чтобы изменить дубликат, не влияя на оригинал, и, конечно же, в этом сценарии будет достаточно глубокого клонирования (только). Я должен был сделать это в системе, где я бы клонировал экземпляр класса домена, применял пользовательские изменения, а затем выполнял сравнение этих двух параметров для проверки своих изменений.
Ответ 4
Метод Object.clone() не указывает, является ли копия подкласса глубокой или мелкой копией, полностью зависящей от конкретного класса. Сам метод Object.clone() выполняет мелкую копию (копирует внутреннее состояние класса Object), но подклассы должны переопределять его, вызывать super.clone() и копировать свое внутреннее состояние по мере необходимости (неглубокое или глубокое).
Он определяет некоторые соглашения, которые вы можете или не должны соблюдать. Для (a.getClass() == a.clone(). GetClass()) для возврата true, super.clone() следует вызывать вместо простого "нового подкласса()", поскольку super.clone() предположительно будет правильно создать экземпляр класса этого объекта (даже в подклассах) и скопировать все внутреннее состояние, включая частные поля, которые не могут быть скопированы подклассами с использованием конструктора копирования, из-за правил видимости. Или вы должны были бы выставить конструктор, который не должен подвергаться, для лучшей инкапсуляции.
Пример:
//simple clone
class A implements Cloneable {
private int value;
public A clone() {
try {
A copy = (A) super.clone();
copy.value = this.value;
return copy;
} catch (CloneNotSupportedException ex) {}
}
}
//clone with deep and shallow copying
class B extends A {
Calendar date;
Date date;
public B clone() {
B copy = (B) super.clone();
copy.date = (Calendar) this.date.clone(); // clones the object
copy.date = this.date; // copies the reference
return copy;
}
}
Глубокая копия обычно используется, когда зависимые объекты изменяются (например, Calendar), и копия должна быть полностью независимой от оригинала.
Когда зависимые объекты являются неизменяемыми (например, Date), совместное использование одного и того же экземпляра обычно не является проблемой, и может быть недостаточно мелкой копии.
При использовании Object.clone() вы должны следовать некоторым правилам, но они достаточно просты, чтобы быть понятными. Вероятно, самая сложная часть - это правильное определение того, насколько глубоко вы должны копировать в свой графический объект. Логическая проблема, а не проблема с языком.
Ответ 5
Я использовал Object.clone() в веб-приложении Spring, чтобы проверить, что изменилось, когда пользователь редактирует/вводит данные в форме для целей аудита.
В начале потока я вызываю метод clone, который был реализован на объекте поддержки формы, используемом в веб-потоке Spring, и сохраните экземпляр клона в сеансе пользователя. После того, как пользователь завершил редактирование данных в форме html и нажал кнопку сохранения, я сравниваю новые значения, привязанные к объекту резервного копирования, к клонированному значению, чтобы определить, какие данные пользователь изменил.
Это сработало хорошо и было очень легко реализовать, у меня на самом деле не возникало проблем с клонированием на Java.