Java中Pass by reference疑问:递归调用中对象引用值为何未保留?
为什么修改Node引用后在递归回溯中没保留值?
嘿,这个问题刚好戳中了Java参数传递里最容易搞混的点——先给你敲个黑板:Java里只有值传递,没有引用传递! 咱们一个个拆解你的测试案例,你就能瞬间明白root的问题出在哪了。
先搞懂核心概念:Java的参数传递
不管是基本类型还是引用类型,Java传递的都是参数的副本:
- 对于基本类型(比如你的
int i),传递的是值的副本——相当于复制了一个一模一样的变量,修改副本完全不影响原变量。 - 对于引用类型(比如你的数组
arr、Node对象root),传递的是对象引用的副本——相当于复制了一把指向对象的“钥匙”,副本和原钥匙都能打开同一个对象,但如果把副本钥匙换成指向另一个对象,原钥匙还是指向原来的对象。
逐个分析你的测试情况
1. 数组arr的修改能保留
数组是引用类型,你传递的是arr引用的副本,但这个副本和原引用都指向同一个数组对象。当你执行arr[0] = 1时,你是在修改这个共享数组对象里的内容,不是修改引用本身。所以不管哪个调用栈里的arr引用,指向的都是同一个数组,回溯时自然能看到修改后的值。
2. 基本类型int i的修改不保留
i是基本类型,传递的是值的副本。当你在times == 2时修改i = 1,你改的只是当前函数栈里的那个i副本,和上层调用的i是完全独立的两个变量,所以上层的i还是初始值0。
3. Node对象root的修改没保留——这是你困惑的核心
你在这里混淆了两个操作:修改引用指向的对象内容和修改引用本身。
- 如果你执行
root.data = 1(修改对象内容),那所有指向这个Node的引用都会看到修改后的值,因为它们都指向同一个对象。 - 但你执行的是
root = root.next(修改引用本身)——这时候你只是把当前函数栈里的root副本(那把复制的钥匙)换成了指向root.next的新引用,而上层调用里的root原引用(你手里的原钥匙)还是指向原来的Node对象!
举个生活化的例子:你有一把钥匙开A房间,你复制了一把给朋友。朋友拿着复制的钥匙,换了一把开B房间的钥匙,但你手里的钥匙还是开A房间的——你打开A房间,里面的东西还是原来的样子;但如果朋友拿着复制钥匙进A房间把家具换了,你进去看也会看到变化。
回到你的代码输出:当times == 2时,你修改了当前栈里的root副本指向next对象,所以下一层递归(times ==3)的root指向next,打印出1;但上层调用(times ==1)和当前times ==2的栈里,原引用并没有被改变,所以回溯时打印的是原来的Node的data值0。
总结一下
- 基本类型:传值副本,改副本不影响原变量;
- 引用类型:传引用副本,改对象内容会影响所有引用;改引用指向,只影响当前栈的副本,和上层无关。
内容的提问来源于stack exchange,提问作者Senthil Kumaran
相关产品推荐
相关产品推荐

