题目
void print(){
for(ListNode node = head; node != null; node = node.next){
System.out.print(node.val);
System.out.print("->");
System.out.print("null");
}
}
void main(){
ListNode node1 = new ListNode(1);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(3);
ListNode head = node1;
node1.next = node2;
node2.next = node3;
print(head);//语句1
node1= node2;
print(head);//语句2
}
//如语句1会输出:123
//那么请问语句2输出什么?
(此题不难,但很考链表概念,愿君花2分钟认真思考后,再看下文)
答案解析
乍看之下,大多认为输出23,我初答也认为是 23,其实不然,答案却是123。
下面以图讲明。
首先须知 Java 中除基本类型外,多是引用类型。所谓引用,类似于内存地址编号。
简单解释:
详细解释:
不管
node1 node2
指来指去,指向哪个节点,都不影响链表遍历结果。因为遍历时,根本没有使用到node1 node2
这三个打酱油的变量。
node3
若看图能懂,下文可不必费时去看。
错误解析
犯错的原因是:将node1 = node2
理解为 节点1整个变成了和节点2一样(val和next都是节点2对应的复制品),所以遍历起来就是 (head)node2 -> node3
输出23。
注意:这里node1 = node2
改变的只是node1 node2
的值,并未影响到节点本身。
若是 node1->next = node2 -> next
,输出才会变成 13(没有了2),想想为什么?
变与不变
其实node1
与node2
二变量(的值)无论如何变化,均未影响到图中右侧黑色的链表实体结构,因它二者只是链表内节点的别名而已,弃之也可。
对于本题,print()
方法每次均从head
开始使用node.next
指针来遍历链表,并未使用到node123
等各节点的别名变量。所以任node1 = node2
,并不影响输出结果。
引用赋值的理解
head = node1
,node1 = node2
如何理解?
变量赋值,无论变量类型怎样,均是以右值赋给左值。
int a = 2, b = 3;
a = b;
//a 变为 3 , b 仍是 3
虽然head、node1、node2 是引用类型变量,原理和基本类型相仿,不过他们的值不再是简单的数字,他们的值是一个地址编号。
head = node1;
//0x0001 0x0001 <-变量的值
// 节点1 节点1 <-指向的节点
node1, node2;
//0x0001 0x0003
// 节点1 节点2
node1 = node2;
//0x0003 0x0003
// 节点2 节点2
head = node1
,是将node1
的值(它存储的地址编号)0x0001
赋值给head
,所以head
的值变为了0x0001
,也即指向了链表第一个节点。
同理,node1 = node2
后,node1
的值变成了0x0003
,指向了链表的第2个节点。
但,不管node1 node2
指来指去,指向哪个节点,都不影响链表遍历结果。因为遍历时,根本没有使用到node1 node2 node3
这三个打酱油的变量。