如何克隆循环链接列表

时间:2019-01-23 22:10:58

标签: java linked-list clone singly-linked-list

我正在尝试以克隆单链列表的方式来克隆循环链表,但是遇到了麻烦。

我试图只将调用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()返回空列表时,程序不会引发此异常。

1 个答案:

答案 0 :(得分:0)

我认为这是问题所在

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

现在您还没有告诉我们CircularlyLinkedList的超类是什么,但是证据是:

  1. 它没有实现Cloneable标记器接口。
  2. 它不会覆盖它从clone继承的Object方法。

通过这种组合,super.clone()将抛出CloneNotSupportedExceptionjavadoc中对此进行了解释。


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

如果您这样做是因为超类具有需要在您创建的克隆中复制的状态,则它(超类)必须提供某种自身的克隆方式;也就是说,它需要执行上述操作之一...或提供“复制构造函数”或类似功能。

如果您只是在进行打字工作,那么您可能应该这样做:

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

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


我注意到此评论:

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

如果该类始终是的意思,则只需对其进行修复以使其与实际操作相符即可。请记住,只有超类是可克隆的……您才可以克隆它!

如果要记录为在所有情况下都这样做,则是“最佳实践”(或其他方法;请参见this),那完全是错误的:

  • 正如我所解释的,您不能在所有情况下都这样做。
  • 尽管有观点认为不建议使用另一种方法来复制超类状态,但子类有权在OO设计中对其超类做出假设。
  • 此外,通过调用super.clone(),您正在假设clone()可以工作!