Java,传值,引用变量

时间:2009-01-31 12:33:45

标签: java reference pass-by-value

在以下示例中,我对理解Java的“pass-by-value”操作有疑问:

public class Numbers {

    static int[] s_ccc = {7};
    static int[] t_ccc = {7};

    public static void calculate(int[] b, int[] c) {

        System.out.println("s_ccc[0] = " + s_ccc[0]); // 7
        System.out.println("t_ccc[0] = " + t_ccc[0]); // 7

        b[0] = b[0] + 9;  
        System.out.println("\nb[0] = " + b[0]); // 16

        c = b;
        System.out.println("c[0] = " + c[0] + "\n"); // 16
    }

    public static void main(String[] args) {

        calculate(s_ccc, t_ccc);

        System.out.println("s_ccc[0] = " + s_ccc[0]);  // 16
        System.out.println("t_ccc[0] = " + t_ccc[0]);  // 7 
    }
}

我知道因为s_ccc是一个引用变量,当我将它赋给方法calculate()并且我对方法中的元素进行一些更改时,即使在我离开方法之后,更改仍然存在。我认为同样应该与t_ccc相同。它又来了 一个引用变量,我将它赋给方法calculate(),并在方法中将引用更改为t_ccc为s_ccc。现在t_ccc应该是一个指向数组的引用变量,它有一个int类型的元素等于16.但是当方法calculate()被保留时,似乎t_ccc指向它的旧对象。为什么会这样?不应该改变它吗?毕竟它是一个参考变量。

此致

5 个答案:

答案 0 :(得分:7)

对Java如何在早期问题“Is Java pass by reference?”中传递变量进行了扩展讨论。 Java确实通过值传递对象引用

在您的代码中,数组(对象)的引用将传递到calculate()。这些引用按值传递,这意味着对bc值的任何更改仅在方法中可见(它们实际上只是s_ccc和{{1的副本}})。这就是t_ccct_ccc从未受到影响的原因。

为了强化这个概念,一些程序员将方法参数声明为main()变量:

final

现在,编译器甚至不允许您更改public static void calculate(final int[] b, final int[] c) b的值。当然,这样做的缺点是你不能再在方法中方便地操作它们了。

答案 1 :(得分:7)

这是一种理解它的简单方法。

Java总是传递参数的副本。如果参数是基本类型(例如整数),则被调用的方法获得原始值的副本。如果参数是引用类型,则被调用的方法获取引用的副本(不是引用的事物的副本)。

当您的main方法开始时,s_ccct_ccc中的每一个都会引用一个不同的数组。 这种情况下,括号表示变量,方括号表示实际的数组结构:

(s_ccc) ---> [7]
(t_ccc) ---> [7]

假设您的意思是calculate(s_ccc, t_ccc),那么在calculate方法的开头:

(s_ccc) ---> [7]  <---(b)
(t_ccc) ---> [7]  <---(c)

本地人bc分别是全局s_ccct_ccc副本

calculcate完成后仍在b[0] = b[0] + 9内:

(s_ccc) ---> [16] <---(b)
(t_ccc) ---> [7]  <---(c)

b 引用的数组中的零(仅)位置已被修改。

c = b中的作业calculate会产生这种情况:

(s_ccc) ---> [16] <---(b)
               ^------(c)
(t_ccc) ---> [7]

本地参考变量c现在包含与b相同的引用。这对全局引用变量t_ccc没有影响,它仍然引用与以前相同的数组。

calculate退出时,其局部变量(在图的右侧)消失。全局变量(在左侧)未在calculate中使用,因此它们不受影响。最后的情况是:

(s_ccc) ---> [16]
(t_ccc) ---> [7]

c_ccct_ccc都没有改变;每个仍然引用与calculate之前相同的数组。调用calculate使用复制的引用更改了s_ccc引用的数组的内容(在b中)。

本地变量c作为t_ccc 副本启动,并在calculate内被操纵,但这既没有改变t_ccc本身也没有改变它的引用数据

答案 2 :(得分:6)

该方法按值接收变量。这些值不能更改(只要方法的调用者看到),但它们中包含的值可以(如果它是一个对象,或者在这种情况下是一个数组)。

因此,当您更改数组中的值b [0]时,可以在方法外部看到更改。但行

c = b;

将更改方法内部的c值,但在方法之外不会看到该更改,因为c的值是按值传递的。

答案 3 :(得分:5)

calculate(s_ccc, s_ccc);表示您实际上没有对t_ccc做任何事情。 但是,如果此行已读取calculate(s_ccc, t_ccc);,则效果仍然相同。

这是因为您在此处为c分配了一个新值:c = b;
将新值分配给引用参数时,引用将丢失 这是改变参考变量和分配新值之间的区别。

答案 4 :(得分:1)

进入calculate()bs_cccct_ccc。因此,改变b[0]会改变s_ccc,如您所见。

然而,作业

c = b;

只有同一个对象c指向的b点,即s_ccc。它不会将b指向的内容复制到c指向的内容。因此,t_ccc保持不变。如果您将以下行添加到calculate():

的末尾
c[0] = c[0] + 5;

s_ccc[0]将是21。