Java模拟链表操作引发对Java传引用的思考实践

来源:互联网 发布:淘宝优惠群怎么找商家 编辑:程序博客网 时间:2024/06/03 10:07

这些天没事在刷刷题,突然遇到一些Java模拟链表的问题,在写的时候也发现了多除与印象中传递引用不同之处,

可能c++基础有半桶水缘故~

先说说Java里面传递参数方法,有传值以及传引用,

传值,就是将基本8数据类型的值传递过去而已

传引用,其实是一种假的传引用,传递的最终是复制一份地址传递过去。

直接说可能太抽象,直接贴出代码慢慢思考:

下面6个test方法,分别会输出怎样的结果呢?

ListNode数据结构:

class ListNode {int val;ListNode next;ListNode(int x) {val = x;}@Overridepublic String toString() {return "ListNode [val=" + val + ", next=" + next + "]";}}

private void quoteTest1() {ListNode l = new ListNode(2);// l2h指向一开始的l,也就是指向l2的头节点ListNode lh = l;for (int i = 0; i < 6; i++) {l.next = new ListNode(1);// 注意此时,l不为null,l的next才为nulll = l.next;}System.out.println("lh is:" + lh);System.out.println("l is:" + l);}private void quoteTest2() {ListNode l = null;// l2h指向一开始的l,也就是指向l2的头节点ListNode lh = l;l = new ListNode(2);for (int i = 0; i < 6; i++) {l.next = new ListNode(1);// 注意此时,l不为null,l的next才为nulll = l.next;}System.out.println("lh is:" + lh);System.out.println("l is:" + l);}private void quoteTest3() {ListNode l = new ListNode(2);boolean firstInitialize = false;ListNode lh = null;// l2h指向一开始的l,也就是指向l2的头节点if (!firstInitialize) {lh = l;firstInitialize = true;}for (int i = 0; i < 6; i++) {l.next = new ListNode(1);// 注意此时,l不为null,l的next才为nulll = l.next;}System.out.println("lh is:" + lh);System.out.println("l is:" + l);}private void quoteTest4() {ListNode l = null, lh = null;boolean firstInitialize = false;for (int i = 0; i < 6; i++) {// 执行之前,l为null。l = new ListNode(2);// l2h指向一开始的l,也就是指向l2的头节点,这段代码单线程下会保证只会执行一次嘛if (!firstInitialize) {lh = l;firstInitialize = true;}// l不为null,但是l.next为null,所以下一次l又为null了。l = l.next;}System.out.println("lh is:" + lh);System.out.println("l is:" + l);}private void quoteTest5() {ListNode l = new ListNode(1), lh = new ListNode(2);// 传递l和lh的引用,事实证明传的是地址的复制,l和l2完全没有改变quoteHelp1(lh, l);System.out.println("lh is:" + lh);System.out.println("l is:" + l);}/** * 仅用于给quoteTest5来使用的工具方法类 里面的业务代码和 quoteTest4 一模一样 *  * @param lh * @param l */private void quoteHelp1(ListNode lh, ListNode l) {boolean firstInitialize = false;for (int i = 0; i < 6; i++) {// 执行之前,l为null。l = new ListNode(2);// l2h指向一开始的l,也就是指向l2的头节点,这段代码单线程下会保证只会执行一次嘛if (!firstInitialize) {lh = l;firstInitialize = true;}// l不为null,但是l.next为null,所以下一次l又为null了。l = l.next;}}private void quoteTest6() {ListNode l = new ListNode(3);l = quoteHelp2();System.out.println("l is:" + l);}/** * quoteTest6的工具方法 *  * @return */private ListNode quoteHelp2() {ListNode l = new ListNode(2);// l2h指向一开始的l,也就是指向l2的头节点ListNode lh = l;for (int i = 0; i < 6; i++) {l.next = new ListNode(1);// 注意此时,l不为null,l的next才为nulll = l.next;}return lh;}

慢慢分析:

quoteTest1方法输出:

lh is:ListNode [val=2, next=ListNode [val=1, next=ListNode [val=1, next=ListNode [val=1, next=ListNode [val=1, next=ListNode [val=1, next=ListNode [val=1, next=null]]]]]]]l is:ListNode [val=1, next=null]

按照正常逻辑去思考,即链表,lh指向这条链表的头节点,最终输出就可以了,由输出可知,是连起来的。


quoteTest2方法输出:

lh is:nulll is:ListNode [val=1, next=null]

由lh只是在最开始的时候赋值了l,但是,此时l也为null,所以其实lh为null,并没有跟着l指向其下一块地址,所以也不存在会是此链表的头节点了。


quoteTest3方法输出:

lh is:ListNode [val=2, next=ListNode [val=1, next=ListNode [val=1, next=ListNode [val=1, next=ListNode [val=1, next=ListNode [val=1, next=ListNode [val=1, next=null]]]]]]]l is:ListNode [val=1, next=null]

quoteTest3内部逻辑代码和quoteTest1其实是相同的,只是增加了一次判断赋值,所以输出基本都是和quoteTest1相同


quoteTest4方法输出:

lh is:ListNode [val=2, next=null]l is:null

这个测试方法我感觉是最纠结的,很像quoteTest1方法,和quoteTest3方法也有点相似,但是输出却与他们截然不同,
很明显,lh在值上仅仅等于头节点,但是头节点,却没有和后面的节点连起来????

上面分析看似比较符合逻辑,一开始我也是这样分析的,然后有个致命的地方,l每次都是null,对l每次循环都是null,

既然是null,你又如何能够用next指向它呢?用next去指向一个null?肯定是不对的。

这也就导致了,这条链根本连不起来,从第二个开始就是脱节了的,每一个都是游离在内存中的ListNode节点。

因为lh只赋值了一次给头节点,所以lh当然只指向了这个头节点。


quoteTest5方法输出:

lh is:ListNode [val=2, next=null]l is:ListNode [val=1, next=null]

由输出可知,l和lh完全没有改变过,假设在quoteTest5方法里面的l和lh分别命名为lTemp和lhTemp的话,其实只要一命名就估计讲清楚了。

看一张简单内存分析图:

这里为了好区分,就把l改成大写的L了,LTemp最终传入方法里面式,是指向的L原来指向的那个内存空间地址,

但是L后面被new了,也就是说它重新指向了,可以假想为指向了下面的长方形内存块。

java里面传引用,也是传值,传的是地址空间块地址。如果此时仅仅对LTemp进行修改操作如:

LTemp.val=9;

那么最终是更改了椭圆块的内容,即实际L指向的内容。


quoteTest6的输出:

l is:ListNode [val=2, next=ListNode [val=1, next=ListNode [val=1, next=ListNode [val=1, next=ListNode [val=1, next=ListNode [val=1, next=ListNode [val=1, next=null]]]]]]]

即最终,l的值是改变了,因为由方法返回之前,把lh的引用块赋值给了l,即l指向了lh指向的内存块地址。


水平有限,如有不对,希望不吝指出!








原创粉丝点击