【2021-07-09】请谈一下值传递与引用传递?Java 中只有值传递么?

未匹配的标注

请移步至::octocat:每日一题 查看更多的题目 ~

请不要忽视这个问题,它也许没有你想的那么简单。绝大部分初学者很难搞懂究竟什么是值传递,什么是引用传递。

很多博客中,作者不仅没有解释清楚“值传递”与“引用传递”,还混淆了很多错误的引导。

所以,在回答这个问题之前,我们先进行一次排雷检查,看一看你是否对值传递与引用传递有着错误的理解:

  • 【观点1】Java 中既有值传递也有引用传递
  • 【观点2】Java 中只有值传递,因为引用的本质就是指向堆区的一个地址,也是一个值。

如果你的观点符合上述两种观点的其中一种,那么你多半没有理解值传递和引用传递的概念。话不多说,接下来我来详细说明究竟什么是值传递,什么是引用传递,以及 Java 中为什么只有值传递。

答:

值传递(Pass by value)与引用传递(Pass by reference)属于函数调用时,参数的求值策略(Evaluation Strategy)。求值策略的关注点在于,求值的时间以及传值方式:

求值策略 求值时间 传值方式
Pass by value 函数调用前 原值的副本
Pass by reference 函数调用前 原值(原始对象)

所以,区别值传递与引用传递的实质并不是传递的类型是值还是引用,而是传值方式,传递的是原值还是原值的副本

如果传递的是原值(原对象),就是引用传递;如果传递的是一个副本(拷贝),就是值传递。再次强调一遍,值传递和引用传递的区别在于传值方式,和你传递的类型是值还是引用没有一毛钱关系!

Java 语言之所以只有值传递,是因为:传递的类型无论是值类型还是引用类型,Java 都会在调用栈上创建一个副本,不同的是,对于值类型而言,这个副本就是整个原始值的复制;而对于引用类型而言,由于引用类型的实例存储在堆中,在栈上只有它的一个引用,指向堆的实例,其副本也只是这个引用的复制,而不是整个原始对象的复制。

我们通过两个程序来理解下:

程序一:

public class Test {
    public static void setNum1(int num){
        num = 1;
    }
    public static void main(String[] args) {
        int a = 2;
        setNum1(a);
        System.out.println(a);
    }
}

程序二:

public class Test2 {
    public static void setArr1(int[] arr){
        Arrays.fill(arr,1);
    }
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};
        setArr1(arr);
        System.out.println(Arrays.toString(arr));
    }
}

程序一输出的结果为:2
程序二输出的结果为:[1,1,1,1,1]

程序一中,Java 会将原值复制一份放在栈区,并将这个拷贝传递到方法参数中,方法里面仅仅是对这个拷贝进行了修改,并没有影响到原值,所以程序一的输出结果为 2。

【2021-07-09】请谈一下值传递与引用传递?Java 中只有值传递么?

程序二中,Java 会将引用的地址复制一份放在栈区,复制的拷贝和原始引用都指向堆区的同一个对象。方法通过拷贝地址找到堆区的实例,对堆区的实例进行修改,而此时,原始引用仍然指向着堆区的实例,程序二的输出结果为:[1,1,1,1,1]

【2021-07-09】请谈一下值传递与引用传递?Java 中只有值传递么?

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇