在以下示例中,我对理解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指向它的旧对象。为什么会这样?不应该改变它吗?毕竟它是一个参考变量。
此致
答案 0 :(得分:7)
对Java如何在早期问题“Is Java pass by reference?”中传递变量进行了扩展讨论。 Java确实通过值传递对象引用。
在您的代码中,数组(对象)的引用将传递到calculate()
。这些引用按值传递,这意味着对b
和c
值的任何更改仅在方法中可见(它们实际上只是s_ccc
和{{1的副本}})。这就是t_ccc
中t_ccc
从未受到影响的原因。
为了强化这个概念,一些程序员将方法参数声明为main()
变量:
final
现在,编译器甚至不允许您更改public static void calculate(final int[] b, final int[] c)
或b
的值。当然,这样做的缺点是你不能再在方法中方便地操作它们了。
答案 1 :(得分:7)
这是一种理解它的简单方法。
Java总是传递参数的副本。如果参数是基本类型(例如整数),则被调用的方法获得原始值的副本。如果参数是引用类型,则被调用的方法获取引用的副本(不是引用的事物的副本)。
当您的main
方法开始时,s_ccc
和t_ccc
中的每一个都会引用一个不同的数组。
这种情况下,括号表示变量,方括号表示实际的数组结构:
(s_ccc) ---> [7]
(t_ccc) ---> [7]
假设您的意思是calculate(s_ccc, t_ccc)
,那么在calculate
方法的开头:
(s_ccc) ---> [7] <---(b)
(t_ccc) ---> [7] <---(c)
本地人b
和c
分别是全局s_ccc
和t_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_ccc
和t_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()
,b
点s_ccc
和c
点t_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。