函数的一点疑惑
相关截图:
我感觉这个解释不太对吧,JAVA函数的参数,如果是引用类型,如例子中的Node,是对象,那么传入的就是一个地址,这个地址在函数中被改变了那么目的不久达到了吗?
正在回答 回答被采纳积分+1
这个问题和这一小节所介绍的问题一模一样,请仔细理解一下,这一小节的介绍的代码错误的原因:https://class.imooc.com/lesson/1667#mid=37628
这里的关键是,Java 的引用和 C++ 的引用不一样。Java 的引用更像是 C++ 的指针。
==========
在我的另一个课程下,有一个同学问了一个类似的问题,我有详细讲解了一遍,你可以参考。
问题:
老师你好想问您一个java 指代的问题
我在main里面创建了一个list , 也就{1, 2}, 然后我把这个list传递给mystery2, 再在mystery2里main重新赋值成{2, 3}, 我不明白为什么在main里面 我打印出来还是{1, 2}而不是{2, 3}
我明白array不是primitive的,所以传递给方法的其实是一个指向该array的地址,那照理说我在mystery2里面重新赋值一个{2,3}, 原本这个地址(也就是存{ 1, 2})的值应该会变成{2, 3} 才对吧, 为什么我直接在一个方法里面改变array的值外面的值就会变,而我重新赋值,它就不会变。
==========
我的回答:
我用你的例子再模拟一遍程序的运行。这里的核心在于,你在 main 里创建的 list 这个引用,和 mystery2 这个函数中的参数 list 引用,是两个变量。为了区分这一点,我把这两个参数名称变得不一样。main 里创建的叫 list,mystery2 的参数叫 argList(因为是个参数)。
class Solution { public static void mystery2(int[] argList){ argList = new int[]{2, 3}; System.out.println(Arrays.toString(argList)); } public static void main(String[] args) { int[] list = {1, 2}; mystery2(list); System.out.println(Arrays.toString(list)); } }
这里的核心是什么?核心在于,当我们 list 传给 mystery2 的时候发生了什么?
答案是,mystery2 创建了一个新的引用,这个新的引用叫 argList,这个新的引用 argList 的赋值是 list,即有 argList = list。此时,list 和 argList 指向了同一个内存空间,即你在 main 开辟的 {1, 2} 的内存空间。用图标是就是这样的:
list ------ | |-----> {1, 2} | argList----
现在,你在 argList 中运行了 argList = new int[](2, 3) 发生了什么?答案是,argList 指向了一个新的内存空间,装载着 {2, 3},但是,argList 的指向变了,不影响 list 的指向。用图标是就是这样的:
list ------ | |-----> {1, 2} argList---------->{2, 3}
当 mystery2 函数结束会发生什么?答案是:argList 这个在 mystery2 中定义的变量,生命周期结束,所以 argList 这个引用变量被销毁。他所指向的内存空间 {2, 3} 由于没有任何引用指向它,也将被 gc 回收。但这一切都不影响 list。
所以,在 main 中,list 依然是 {1, 2}。
这一切等效于下面的程序,list 打印结果仍然是 {1, 2}(只不过 argList 的生命周期没有结束。)
public static void main(String[] args) { int[] list = {1, 2}; int[] argList = list; argList = new int[]{2, 3}; System.out.println(Arrays.toString(list)); }
==========
那么为什么如果我们在 mystery 中,不是改变 argList 的指向,而是改变 argList 的某一项,list 也会变?因为 argList 和 list 指向的是同一个内存空间,所以,改变 argList 指向的内存空间的值,通过 list 也能看到。
请仔细体会他们的区别。
这等效于下面的程序,list 将变成 {1, 3}
public static void main(String[] args) { int[] list = {1, 2}; int[] argList = list; argList[1] = 3; System.out.println(Arrays.toString(list)); }
==========
请仔细理解这二者的区别。我建议你再回顾一下这一小节,体会一下这一小节我所讲解的问题,和你提出的问题的共性在哪里?https://class.imooc.com/lesson/1580#mid=36148
(另外,为什么我们在 BST 的各种操作中,改变 node 的值,比如改变 node->val,node->left, node->right,就没有这个问题?本质和你提出的问题是一致的。)
==========
这个问题非常非常重要。在任何语言中都存在,只不过不同的语言,可能表现出的形式不一样。甚至在一些语言中会表现的更复杂,比如 C++ 中。这是因为,Java 的任何非基本类型,都是引用。但是 C++ 中任意一个变量,都有可能是值,或者是指针,或者是引用(C++ 中对应用的定义和 Java 不一样,Java 中的引用相当于 C++ 中的指针),所以情况可能更复杂,但是也更灵活。
继续加油!:)
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星