java semantic reference

来源:1-1 为什么要研究树结构

weixin_慕圣6334738

2021-10-01 05:53:43

老师你好想问您一个java 指代的问题https://img.mukewang.com/climg/615630ad09b4030608800474.jpg


我在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的值外面的值就会变,而我重新赋值,它就不会变

写回答

1回答

liuyubobobo

2021-10-01

这个问题本质上和我在这一小节讲解的问题是一致的:https://class.imooc.com/lesson/1580#mid=36148 你的例子里的 list,就相当于我这个例子里的 node。


我用你的例子再模拟一遍程序的运行。这里的核心在于,你在 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++ 中的指针),所以情况可能更复杂,但是也更灵活。


继续加油!:)

0
heixin_慕圣6334738
hp>很不错的回答,感谢老师!

h021-10-01
共1条回复

算法与数据结构

波波老师5年集大成之作,算法与数据结构系统学习,考试、面试、竞赛通用

2638 学习 · 1091 问题

查看课程

相似问题

java语法问题

回答 1

回答 1

回答 1

回答 1