我正在尝试在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());
}
}
答案 0 :(得分:5)
正如您正确指出的那样,惯例是在super.clone()
的实现开始时始终调用clone()
。来自API docs on Object#clone()
:
按照惯例,返回的对象应该通过调用super.clone来获得。如果一个类及其所有超类(Object除外)遵循这个约定,那么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
,并且此实现将创建一个正确类型的实例({{1}}情况)!
答案 1 :(得分:1)
正如其他人所解释的那样,如果你要覆盖clone
,你应该遵守其合同。
如果您喜欢当前拥有它的方式,只需将DoubleLinkedList
设为Cloneable
,然后将您的实现转换为复制构造函数或静态工厂方法。静态工厂方法还具有为泛型类型参数提供一些类型推理的附加好处。
P.S。 LinkedList
是双重链接列表。
答案 2 :(得分:0)
如果您通过创建新列表并添加源中的所有元素来执行此操作,那么您可以执行以下操作:
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中)。正确的方法是实际克隆每个元素并添加克隆以确保列表是独立的。请注意,只有在更改元素的属性时才会发生这种情况,而不是在列表中添加,移动和删除它们时。
编辑:刚才意识到,由于它是一个链表,下一个/前一个元素是元素的属性,所以即使添加,删除也会影响这两个列表。
答案 3 :(得分:0)
“约定”调用super.clone()
的原因是为了确保克隆对象的最终类型与正在克隆的对象匹配。例如,如果你在DoubleLinkedList
方法中实例化你自己的新clone()
,那么现在很好,但是后来如果一个子类无法覆盖clone()
,它将最终返回一个克隆,一个DoubleLinkedList
而不是它自己的类。 (它也可能无法克隆其他字段,如果有的话,可能!所以存在更大的问题。)
从这个意义上说,传统方法是首选,而且确实很笨重。
但是,这两种实现都存在类似的问题:您没有深度复制数据结构。克隆只是一个浅警察。这可能不是调用者所期望的。您需要遍历并使用值的克隆替换DoubleLinkedList
中的每个值,对于其他非原始字段也是如此。
从这个意义上讲,传统方法会在这里给出错误的结果!你需要第三种方式。您的第一种方法可能只是工作,除了您需要添加element.clone()
之外。