题
我正在尝试实施 clone()
A上的方法 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()
在Overriden克隆方法中, Object.clone()
最终将被调用,此实施将创建适当类型的实例(IntDoubleLinkedList
在这种情况下)!
其他提示
正如其他人所解释的那样,如果您要覆盖 clone
您应该遵守其合同。
如果您喜欢当前的方式,只需做 DoubleLinkedList
不是 Cloneable
并将您的实现变成复制构造函数或静态工厂方法。静态工厂方法也具有为通用类型参数提供一些类型推理的额外好处。
PS 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()
例如。