添加新节点时,链表的浅表副本不反映更改

http://img3.mukewang.com/62e0af08000122aa02930221.jpg

我已经阅读了很多资料,但如果不在这里提问,我似乎无法消除我的困惑。根据该图,当我使用 clone() 创建链表的浅表副本时。一个新的链表被创建,原始的头变量的引用值被复制到克隆的,其余的节点被共享。因此,如果我使用克隆添加一个新节点,这应该对原始节点可见,不是吗?但是当打印 list1 时,值 3 被省略。有人能告诉我为什么吗?


LinkedList<Integer> list1 = new LinkedList<>();

l1.add(1);

l1.add(2);

LinkedList<Integer> list2 = (LinkedList) l1.clone();

l2.add(3); 


天涯尽头无女友
浏览 86回答 2
2回答

九州编程

clone()创建新LinkedList结构并返回对第一个节点的新引用。这两个 s 之间的关系LinkedList是它们共享同一个节点values。当您对旧列表或新列表进行一些add\remove操作时,这些操作不会更改其他列表。这就是我们这样做的原因copy——我们不想在更改副本时更改原始链表结构。从LinkedList.clone文档:返回 this 的浅拷贝LinkedList。(元素本身没有被克隆。) @return这个LinkedList实例的浅拷贝考虑下面的例子:import java.util.LinkedList;import java.util.concurrent.atomic.AtomicInteger;public class LinkedListsApp {&nbsp; &nbsp; public static void main(String[] args) throws Exception {&nbsp; &nbsp; &nbsp; &nbsp; LinkedList<AtomicInteger> l1 = new LinkedList<>();&nbsp; &nbsp; &nbsp; &nbsp; l1.add(new AtomicInteger(100));&nbsp; &nbsp; &nbsp; &nbsp; l1.add(new AtomicInteger(200));&nbsp; &nbsp; &nbsp; &nbsp; LinkedList<AtomicInteger> l2 = (LinkedList) l1.clone();&nbsp; &nbsp; &nbsp; &nbsp; l2.add(new AtomicInteger(300));&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(l1);&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(l2);&nbsp; &nbsp; &nbsp; &nbsp; // change element on first list&nbsp; &nbsp; &nbsp; &nbsp; l1.get(0).incrementAndGet();&nbsp; &nbsp; &nbsp; &nbsp; System.out.println();&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("After change internal state of first element");&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(l1);&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(l2);&nbsp; &nbsp; }}上面的代码打印:[100, 200][100, 200, 300]After change internal state of first element[101, 200][101, 200, 300]正如我们所看到的,当我们从第一个列表更改第一个元素的内部状态时,第二个列表也可以看到它。因此,没有每个元素值的深层副本,而是结构的副本 - 节点和顺序的副本。为了清楚起见,让我们看一下实现Java 8:public Object clone() {&nbsp; &nbsp; LinkedList<E> clone = superClone();&nbsp; &nbsp; // Put clone into "virgin" state&nbsp; &nbsp; clone.first = clone.last = null;&nbsp; &nbsp; clone.size = 0;&nbsp; &nbsp; clone.modCount = 0;&nbsp; &nbsp; // Initialize clone with our elements&nbsp; &nbsp; for (Node<E> x = first; x != null; x = x.next)&nbsp; &nbsp; &nbsp; &nbsp; clone.add(x.item);&nbsp; &nbsp; return clone;}看看for-each循环。它遍历原始列表并将值添加到clone列表中。方法add创建新Node对象,该对象存储与原始列表相同的值:x.item。

忽然笑

clone() 方法创建第一个链表的精确副本,然后将其返回到此处的 l2。它所做的是创建一个新实例并从原始实例复制所有字段,然后将其返回给 l2 对象。如果我们想要的只是浅拷贝,我们可以简单地使用赋值运算符,在这种情况下,对 l1 所做的任何更改都将反映在 l2 上,因为不会创建新对象,而只会创建引用的副本。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java