在 LinkedList 上实现克隆

发布于 2024-09-03 20:37:24 字数 774 浏览 5 评论 0原文

我正在尝试在 DoubleLinkedList 上实现 clone() 方法。现在的问题是,通过“约定”实现它比仅仅创建一个新的 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());
    }
}

I am trying to implement a clone() method on a DoubleLinkedList. Now, the problem is that implementing it by "the convention" is a lot more troublesome than just creating a new DoubleLinkedList and filling it with all the elements of my current DoubleLinkedList.

Is there any inconvenient I am not seeing when doing that?

Here is my current approach:

@Override
public DoubleLinkedList<T> clone() {
    DoubleLinkedList<T> dll = new DoubleLinkedList<T>();

    for (T element : dll) {
        dll.add(element);
    }

    return dll;
}

Here is what it would be by the convention:

@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());
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

青衫儰鉨ミ守葔 2024-09-10 20:37:25

如果您通过创建一个新列表并添加源中的所有元素来做到这一点,那么如果您执行以下操作:

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)中。正确的方法是实际克隆每个元素并添加克隆以确保列表是独立的。请注意,只有当您更改元素的属性时才会发生这种情况,而当您从列表中添加、移动、删除它们时则不会发生这种情况。

编辑:刚刚意识到,由于它是一个链接列表,下一个/上一个元素是该元素的属性,因此即使添加、删除也会影响两个列表。

If you do it by creating a new list and adding all the elements from the source, if you then do something like:

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 will be "new value" in both lists (the same the other way around; if you change it in l1, changes will appear in l2). The correct way would be to actually clone every element and the add the clone to ensure the lists are independent. Take note that this only happens if you change properties of the elements, not if you add, move, delete them from the list.

Edit: just realized that since it's a linked list, the next/previous elements are properties of the element, so even adding, deleting, will affect both list.

樱花坊 2024-09-10 20:37:25

“约定”调用 super.clone() 的原因是为了确保克隆对象的最终类型与正在克隆的对象匹配。例如,如果您在 clone() 方法中实例化自己的新 DoubleLinkedList,那么现在很好,但稍后如果子类无法覆盖 clone() 它将最终返回一个 DoubleLinkedList 的克隆,而不是它自己的类。 (它也可能无法克隆其附加字段(如果有的话)!因此存在更大的问题。)

从这个意义上说,传统方法是首选,而且它确实很笨重。

然而,这两种实现都有类似的问题:您没有深度复制数据结构。克隆人只是一个肤浅的警察。这可能不是调用者所期望的。您需要检查 DoubleLinkedList 中的每个值并将其替换为该值的克隆,对于其他非原始字段也是如此。

从这个意义上说,传统方法在这里会给出错误的结果!你需要第三条路。您的第一个方法可能几乎有效,只是您需要添加 element.clone() 例如。

The reason the "convention" is to call super.clone() is to ensure the ultimate type of the cloned object matches the object that is being cloned. For example if you instantiate your own new DoubleLinkedList in the clone() method, well that's nice for now, but later if a subclass fails to override clone() it will end up returning a clone that is a DoubleLinkedList instead of its own class. (It'll also fail to clone its additional fields, if any, probably! so there are larger issues.)

In that sense, the conventional method is preferred, and it is indeed clunky.

Both implementations, however, have a similar problem: you're not deep-copying the data structures. The clone is only a shallow cop. This is probably not what the caller expects. You would need to go through and replace each value in the DoubleLinkedList with a clone of the value, and likewise for other non-primitive fields.

In that sense, the conventional method is going to give the wrong result here! You need a third way. Your first method probably just about works, except that you need to add element.clone() for example.

平生欢 2024-09-10 20:37:24

正如您正确指出的那样,惯例是始终在 clone() 实现的开头调用 super.clone() 。来自 API 文档 Object#clone()

按照惯例,返回的对象应该通过调用super.clone来获取。如果一个类及其所有超类(Object 除外)都遵守此约定,则 x.clone().getClass() == x.getClass() 的情况将会出现。

您的第一次尝试(不使用 super.clone())存在以下问题:

假设我有

class IntDoubleLinkedList extends DoubleLinkedList<Integer> implements Cloneable

(并且 IntDoubleLinkedList 不费心去覆盖 clone()< /code>) 然后我运行以下代码:

IntDoubleLinkedList idll = new IntDoubleLinkedList();
IntDoubleLinkedList idll2 = (IntDoubleLinkedList) idll.clone();

会发生什么? 你的 DoubleLinkedList 的clone方法将被执行,如果它没有通过super.clone(),则返回一个DoubleLinkedList的实例> 反过来又不能转换为 IntDoubleLinkedList将会抛出ClassCastException

那么super.clone()如何解决这个问题呢?好吧,如果每个人都坚持在重写克隆方法中调用 super.clone() 的约定,则最终将调用 Object.clone(),并且此实现将创建正确类型的实例(在本例中为 IntDoubleLinkedList)!

As you correctly point out, the convention is to always call super.clone() in the beginning of an implementation of clone(). From the API docs on Object#clone():

By convention, the returned object should be obtained by calling super.clone. If a class and all of its superclasses (except Object) obey this convention, it will be the case that x.clone().getClass() == x.getClass().

Your first attempt (without using super.clone()) has the following problem:

Suppose I have

class IntDoubleLinkedList extends DoubleLinkedList<Integer> implements Cloneable

(and that IntDoubleLinkedList does not bother to override clone()) and I run the following code:

IntDoubleLinkedList idll = new IntDoubleLinkedList();
IntDoubleLinkedList idll2 = (IntDoubleLinkedList) idll.clone();

What will happen? The clone method of your DoubleLinkedList will be executed, which, if it doesn't go through super.clone(), returns an instance of DoubleLinkedList which in turn can not be casted to an IntDoubleLinkedList. A ClassCastException will be thrown!

So how does super.clone() solve this issue? Well, if everybody stick to the convention of calling super.clone() in an overriden clone method, Object.clone() will eventually be called, and this implementation will create an instance of a proper type (IntDoubleLinkedList in this case)!

装迷糊 2024-09-10 20:37:24

正如其他人所解释的,如果您要覆盖clone,您应该遵守它的合同。

如果您喜欢当前的方式,只需将 DoubleLinkedList 设置为 Cloneable 并将您的实现转换为复制构造函数或静态工厂方法即可。静态工厂方法还有一个额外的好处,即为泛型类型参数提供一些类型推断。

PS LinkedList 一个双向链表。

As others have explained, if you're going to override clone you should obey its contract.

If you like the way you currently have it, just make DoubleLinkedList not Cloneable and turn your implementation into a copy constructor or static factory method. A static factory method has the added benefit of providing a bit of type inferencing for generic type arguments, too.

P.S. LinkedList is a doubly-linked list.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文