java - 为什么 Java 中 LinkedList.add() 的内置实现不将元素添加到 LinkedList 的浅副本,而是自定义实现添加?

标签 java collections linked-list

在下面的示例中,在“main”中,将 LinkedList l1 克隆到 l2 后,当我将元素添加到 l2 时,我在 l1 中没有得到 300。

但是,在“addTwoLists”方法中,当我使用自定义实现时,将任何元素添加到“rohit”也会将其添加到“first”。

package hackerrank;

import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;

class Node1 implements Cloneable{
    int data;
    Node1 next;
    Node1(int x){
        this.data=x;
        this.next=null;
    }
    Node1 (){
        
    }
    protected Node1 clone() throws CloneNotSupportedException {
        return (Node1) super.clone();
    }
    
}
public class MS_linkedlist_copy {

    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        
         LinkedList<AtomicInteger> l1 = new LinkedList<>();
            l1.add(new AtomicInteger(100));
            l1.add(new AtomicInteger(200));

            LinkedList<AtomicInteger> l2 = (LinkedList) l1.clone();
            l2.add(new AtomicInteger(300));

            System.out.println(l1);
            System.out.println(l2);

            // change element on first list
            l1.get(0).incrementAndGet();

            System.out.println();
            System.out.println("After change internal state of first element");
            System.out.println(l1);
            System.out.println(l2);
            
            
            
        Node1 first = new Node1(1);
        Node1 second = new Node1(2);
        first.next= second;
        
        
        Node1 third = new Node1(3);
        Node1 fourth = new Node1(4);
        third.next=fourth;
        
        addTwoLists(first, third);
    }
    
    static Node1 reverse(Node1 head){
        Node1 prev =null;
        while(head!=null){
            Node1 next_node = head.next;
            head.next = prev;
            prev=head;
            head=next_node;
        }
        return prev;
    }
    //
    static Node1 addTwoLists(Node1 first, Node1 second){
        System.out.println(first.data);
        Node1 rohit = null;
        try {
            rohit = (Node1)first.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        rohit.data=1000;
        rohit.next.data=1000;
        System.out.println(first.data);
        System.out.println(rohit.data);
        
        Node1 rohit2= rohit;
        while(rohit.next!=null) {
            rohit= rohit.next;
        }
        Node1 rohit_add = new Node1(2000);
        rohit.next = rohit_add;
        System.out.println(first.data);
        System.out.println(rohit2.data);
//      rohit = first;
//        rohit= reverse(rohit); 
//        reverse(second);
//        System.out.println(first.data);
//        System.out.println(rohit.data);
        
        
        return null;
        }

}

我尝试将元素添加到自定义的浅拷贝中,该副本已成功添加到主列表中。但是,在尝试将元素添加到内置 LinkedList 的浅拷贝后,这些元素不会添加到原始列表中。我试图了解内置 LinkedList 中发生了什么。

最佳答案

不同之处在于 LinkedList.clone 还会复制整个链表中的所有节点,而 Node1.clone 仅复制一个节点,而不是链接到它的任何节点。

您可以找到 LinkedList.clone 的实现 here ,

public Object clone() {
    LinkedList<E> clone = superClone();

    // Put clone into "virgin" state
    clone.first = clone.last = null;
    clone.size = 0;
    clone.modCount = 0;

    // Initialize clone with our elements
    for (Node<E> x = first; x != null; x = x.next)
        clone.add(x.item);

    return clone;
}

请注意,它在循环中对克隆列表(此处称为clone)调用add。每次调用 add 都会创建一个新的链表节点。

请注意,这仍然是浅拷贝,因为节点中的数据没有被克隆。例如,如果列表存储 String 对象,则不会创建新字符串。

因此,克隆之后,您实际上会得到两个带有内置 LinkedList 的“链”:

O-O-O
O-O-O

而对于您的 Node1,由于只克隆了一个节点,因此您会得到如下所示的结果:

 first -> O
           \
            -O-O
           /
rohit2 -> O

列表的两个“头”共享相同的“尾”,因此向列表末尾添加一个元素会将其添加到两个列表中。

您可以重写您的克隆,以便它复制所有节点。一种简单的方法是递归地执行:

protected Node1 clone() throws CloneNotSupportedException {
    Node1 newNode = new Node1(this.data);
    if (next != null) {
        newNode.next = next.clone();
    }
    return newNode;
}

关于java - 为什么 Java 中 LinkedList.add() 的内置实现不将元素添加到 LinkedList 的浅副本,而是自定义实现添加?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75498323/

相关文章:

java - 无法解析 Intent 构造函数

java - 如何在加载类的字节码之前对其进行操作?

c# - 无序无重复的线程安全集合

c - 从文件中搜索链接列表

java - AWS Lambda : How to extract a tgz file in a S3 bucket and put it in another S3 bucket

java - itext多重签名

java - 如何随机化列表中的条目,以便用户每次都能看到不同的 DailyPrayer?

Java 8. 使用收集器将值列表分组到范围列表中

c - 尝试在 C 中创建一个空链表

java - 如何在java中创建链表?