在 LinkedList 上实现克隆
我正在尝试在 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您通过创建一个新列表并添加源中的所有元素来做到这一点,那么如果您执行以下操作:
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:
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.
“约定”调用 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 newDoubleLinkedList
in theclone()
method, well that's nice for now, but later if a subclass fails to overrideclone()
it will end up returning a clone that is aDoubleLinkedList
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.正如您正确指出的那样,惯例是始终在
clone()
实现的开头调用super.clone()
。来自 API 文档Object#clone()
:您的第一次尝试(不使用
super.clone()
)存在以下问题:假设我有
(并且
IntDoubleLinkedList
不费心去覆盖clone()< /code>) 然后我运行以下代码:
会发生什么? 你的
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 ofclone()
. From the API docs onObject#clone()
:Your first attempt (without using
super.clone()
) has the following problem:Suppose I have
(and that
IntDoubleLinkedList
does not bother to overrideclone()
) and I run the following code:What will happen? The clone method of your
DoubleLinkedList
will be executed, which, if it doesn't go through super.clone(), returns an instance ofDoubleLinkedList
which in turn can not be casted to anIntDoubleLinkedList
. AClassCastException
will be thrown!So how does
super.clone()
solve this issue? Well, if everybody stick to the convention of callingsuper.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)!正如其他人所解释的,如果您要覆盖
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
notCloneable
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.