Реализация клона в LinkedList
Вопрос
Я пытаюсь внедрить clone()
Метод на DoubleLinkedList
. Анкет Теперь проблема в том, что реализация его «конвенцией» намного более хлопотно, чем просто создание нового DoubleLinkedList
и заполнить его всеми элементами моего нынешнего DoubleLinkedList.
Есть ли какие -то неудобные, которые я не вижу, когда делаю это?
Вот мой текущий подход:
@Override
public DoubleLinkedList<T> clone() {
DoubleLinkedList<T> dll = new DoubleLinkedList<T>();
for (T element : dll) {
dll.add(element);
}
return dll;
}
Вот что было бы по соглашению:
@Override
public DoubleLinkedList<T> clone() {
try {
DoubleLinkedList<T> dll = (DoubleLinkedList<T>)super.clone();
//kinda complex code to copy elements
return dll;
} catch (CloneNotSupportedException e) {
throw new InternalError(e.toString());
}
}
Решение
Когда вы правильно указываете, соглашение всегда звонить super.clone()
В начале реализации clone()
. Анкет От API документы на Object#clone()
:
По соглашению возвращаемый объект должен быть получен путем вызова Super.clone. Если класс и все его суперклассы (кроме объекта) подчиняются этому соглашению, это будет тот случай, когда x.clone (). GetClass () == x.getClass ().
Ваша первая попытка (без использования super.clone()
) имеет следующую проблему:
Предположим, у меня есть
class IntDoubleLinkedList extends DoubleLinkedList<Integer> implements Cloneable
(и это IntDoubleLinkedList
не пытается переопределять clone()
) и я запускаю следующий код:
IntDoubleLinkedList idll = new IntDoubleLinkedList();
IntDoubleLinkedList idll2 = (IntDoubleLinkedList) idll.clone();
Что случится? Метод клона ваш DoubleLinkedList
будет выполнено, что, если он не пройдет через Super.Clone (), возвращает экземпляр DoubleLinkedList
который, в свою очередь, не может быть поднят на IntDoubleLinkedList
. А ClassCastException
будет брошен!
Так как это super.clone()
решить эту проблему? Ну, если все придерживаются соглашения о звонке super.clone()
в методе переопределения клонов, Object.clone()
в конечном итоге будет вызвана, и эта реализация создаст экземпляр надлежащего типа (IntDoubleLinkedList
в таком случае)!
Другие советы
Как объяснили другие, если вы собираетесь переопределить clone
Вы должны подчиняться его контракту.
Если вам нравится, как у вас есть в настоящее время, просто сделайте DoubleLinkedList
нет Cloneable
и превратите свою реализацию в конструктор копирования или метод статического завода. Статический фабричный метод имеет дополнительное преимущество в предоставлении небольшого типа вывода для общих аргументов.
Пса LinkedList
является Список вдвойне связанный.
Если вы сделаете это, создав новый список и добавив все элементы из источника, если вы сделаете что -то вроде:
DoubleLinkedList<Foo> l1 = new DoubleLinkedList<Foo>();
l1.add (new Foo(params));
DoubleLinkedList<Foo> l2 = l1.clone();
Foo foo = l2.get(0);
foo.setProperty("new Value");
Foo.Property будет «новым значением» в обоих списках (наоборот, наоборот; если вы измените его в L1, изменения появятся в L2). Правильным способом будет то, чтобы фактически клонировать каждый элемент, и добавить клон, чтобы убедиться, что списки являются независимыми. Обратите внимание, что это происходит только в том случае, если вы измените свойства элементов, а не в том случае, если вы добавите, перемещайте, удалите их из списка.
РЕДАКТИРОВАТЬ: только что понял, что, поскольку это связанный список, следующие/предыдущие элементы являются свойствами элемента, поэтому даже добавление, удаление, повлияет на оба списка.
Причина, по которой «Конвенция» состоит в том, чтобы позвонить super.clone()
это обеспечить, чтобы конечный тип клонированного объекта соответствует клонированию объекта. Например, если вы создаете свой новый новый DoubleLinkedList
в clone()
Метод, ну, это хорошо, но позже, если подкласс не может переопределить clone()
в конечном итоге вернет клон, который DoubleLinkedList
вместо собственного класса. (Это также не сможет клонировать свои дополнительные поля, если таковые имеются, вероятно, так что есть большие проблемы.)
В этом смысле обычный метод является предпочтительным, и он действительно неуклюжий.
Обе реализации, однако, имеют аналогичную проблему: вы не глубоко укорените структуры данных. Клон - это всего лишь мелкий полицейский. Это, вероятно, не то, что ожидает вызывающий абонент. Вам нужно пройти и заменить каждое значение в DoubleLinkedList
с клоном значения, а также для других невимичных полей.
В этом смысле обычный метод даст здесь неправильный результат! Вам нужен третий путь. Ваш первый метод, вероятно, просто работает, за исключением того, что вам нужно добавить element.clone()
Например.