如何克隆循环链表

How to Clone a Circularly Linked List

我正在尝试以与克隆单向链表相同的方式克隆循环链表,但遇到了问题。

我试图在 public 方法 clone() 中只保留调用 clone() 的受保护方法的行,但程序仍然会抛出错误。

public static void main(String[] args) throws CloneNotSupportedException 
  {

  CircularlyLinkedList<String> circularList = new 
  CircularlyLinkedList<String>();
  circularList.addFirst("1");
  circularList.addLast("2");
  circularList.addLast("3");
  circularList.addLast("4");


  CircularlyLinkedList<String> newList = new CircularlyLinkedList<String>();
  newList= circularList.clone();
  System.out.println(newList);
  }
@SuppressWarnings("unchecked")
public CircularlyLinkedList<E> clone() throws CloneNotSupportedException 
{
  // always use inherited Object.clone() to create the initial copy
    CircularlyLinkedList<E> other = (CircularlyLinkedList<E>) super.clone(); // safe cast
    if (size > 0) {                    // we need independent chain of nodes
        other.head = new Node<>(head.getElement(), null);
        Node<E> walk = head.getNext();      // walk through remainder of original list
        Node<E> otherTail = other.head;     // remember most recently created node
        while (walk != null) {              // make a new node storing same element
          Node<E> newest = new Node<>(walk.getElement(), null);
          otherTail.setNext(newest);     // link previous node to this one
          otherTail = newest;
          walk = walk.getNext();
        }
      }
    return other;

}

此代码在使用单链表时有效。预期的输出是打印两次的链表,但实际输出是抛出的异常"CloneNotSupported"。请注意,当 clone() returns 一个空列表时,程序不会抛出此异常。

这里是问题所在,我认为:

CircularlyLinkedList<E> other = (CircularlyLinkedList<E>) super.clone(); 

现在你还没有告诉我们 CircularlyLinkedList 的 superclass 是什么,但证据是:

  1. 它没有实现 Cloneable 标记接口。
  2. 它不会覆盖它继承自 Objectclone 方法。

使用该组合,super.clone() 将抛出 CloneNotSupportedExceptionjavadoc.

中对此进行了解释

但真正的问题是你为什么打电话给 super.clone()

如果你这样做是因为 superclass 的状态需要复制到你正在创建的克隆中,那么它(superclass)必须提供某种克隆自身的方法;即它需要执行上述操作之一......或提供 "copy constructor" 或类似的。

如果您这样做只是为了让打字工作,那么您可能应该这样做:

    CircularlyLinkedList<E> other = new CircularlyLinkedList<>(); 

其中构造函数(如有必要,可以 private 创建一个实例,您可以开始填写该实例。请注意,这是类型安全的。


我注意到这条评论:

// always use inherited Object.clone() to create the initial copy

如果它的意思是 always for this class,那么只需修改它以匹配您的实际操作。请记住,只有当 superclass 是可克隆的时,您才可以……目前它不是!

如果要记录在所有情况下都"best practice"(或其他;参见this)这样做,那是完全错误的:

  • 正如我所解释的,您不能在所有情况下都这样做。
  • 虽然有人认为使用另一种方法来复制 superclass 状态可能是不可取的,但 subclass 有权在 OO 中对其 superclass 进行假设设计。
  • 此外,通过调用 super.clone(),您是在假设......clone() 会起作用!