C#中ListNode引用副本操作:为何有的修改影响原引用有的不?
引用类型变量操作的本质差异解析
先明确核心逻辑:C#里的引用类型变量,存储的是对象在内存中的地址(引用),而非对象本身。两个变量指向同一对象时,操作分为修改变量的引用指向和修改变量指向的对象的成员两类,这两种操作的结果完全不同。
第一种场景:CreateList函数中的temp操作
先看CreateList里的关键代码:
var root = new ListNode(); var temp = root; // temp和root指向同一个ListNode对象(记为对象A) // 循环内的核心操作 while (temp.next != null) temp = temp.next; // 改变temp变量的指向:从对象A切换到A.next、A.next.next...
这里的temp = temp.next是给temp变量重新赋值,让它指向另一个对象,但root变量的指向始终是最初的对象A,所以root不会被改变。
而后续的temp.next = new ListNode(array[i]),是修改temp当前指向的对象的next成员,这个修改会同步到链表结构中,但root本身的指向还是对象A,所以返回的root依然是链表的头节点。
第二种场景:修改val的操作
再看这段测试代码:
var listNode1 = new ListNode(1); // 创建对象B,listNode1指向B var listNode2 = listNode1; // listNode2也指向B listNode2.val = 2; // 修改对象B的val成员 Console.WriteLine(listNode1.val); // 输出2,因为listNode1同样指向B
这里的listNode2.val = 2是直接修改listNode2指向的对象B的成员变量,由于listNode1和listNode2指向同一个对象B,所以通过listNode1访问val时,看到的是修改后的值。
总结差异
- 执行
temp = temp.next时,是改变temp变量自身的引用指向,和root变量的指向无关,因此root不受影响; - 执行
listNode2.val = 2时,是修改共享对象的成员,所有指向该对象的变量都会同步看到修改结果。
可以用通俗的比喻理解:把对象比作房子,引用变量比作钥匙。
temp = temp.next相当于你把自己的钥匙换成了隔壁房子的钥匙,朋友手里的钥匙还是原来房子的;listNode2.val = 2相当于你用钥匙打开房子,把里面的电视换成新的,朋友用他的钥匙开门,看到的也是新电视。
内容的提问来源于stack exchange,提问作者Test123 Test234
相关产品推荐
相关产品推荐

