在LinkedList上实现克隆

时间:2010-06-03 11:21:18

标签: java cloning cloneable

我正在尝试在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());
    }
}

4 个答案:

答案 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()之外。