之前写了个关于Java值传递和引用传递的博客,自以为在函数参数传递这方面已经了解得比较清楚了。可是今天在做剑指offer算法题二叉搜索树和双向链表时,提交了好几次代码都没对,最后发现是函数参数传递理解出了问题。
这是正确的代码:
public TreeNode covertNode(TreeNode root, TreeNode lastlist) {
if (root == null)
return null;
TreeNode cur = root;
if (cur.left != null)
lastlist = covertNode(cur.left,lastlist);
//改变左右节点
cur.left = lastlist;
if (lastlist != null)
lastlist.right = cur;
lastlist = cur;
if (cur.right != null)
lastlist = covertNode(cur.right,lastlist);
return lastlist;
}
这是错误的代码:
public void ConvertCore(TreeNode pRootOfTree,TreeNode listLastNode){
if(pRootOfTree==null)
return;
if(pRootOfTree.left!=null)
ConvertCore(pRootOfTree.left,listLastNode);
//改变左右节点
pRootOfTree.left = listLastNode;
if(listLastNode!=null)
listLastNode.right = pRootOfTree;
listLastNode = pRootOfTree;
if(pRootOfTree.right!=null)
ConvertCore(pRootOfTree.right,listLastNode);
}
可以看到这两段代码主要区别是listLastNode有没有进行显示赋值。
我以为Java是引用传递,在方法中改变了引用数据类型的参数之后,在方法外面该引用数据类型的参数也是会被改变的。可实际上不一定是这样的。看一下下面一段代码。
public class test1 {
public static void main(String[] args) {
TreeNode node = null;
change(node);
System.out.println(node);
}
static void change(TreeNode node) {
node = new TreeNode(1);
System.out.println(node);
}
}
输出值为:
test.TreeNode@3d4eac69
null
可以看到在主函数里面,node的值并未被改变。
搜了一些资料之后,理解了一下这个问题。在Java中(包括其他大部分语言),执行方法之前,编译器会将参数的值压入堆栈之中,其中引用数据类型压入的为引入变量的地址。方法结束之后,编译器会将之前压入堆栈的引用变量的地址重新赋给引用变量。故而Java中方法不能改变引用变量参数的地址(指向的对象)。
而我之前误以为Java能改变引用数据类型的参数的实参是因为在之前的测试程序是改变了ArrayList形参的值,方法结束之后,由于指向的是同一个对象,实参的值当然也会被改变。让我产生了错觉。