在以下示例中,我对理解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指向它的旧对象.为什么会这样?不应该改变它吗?毕竟它是一个参考变量.
问候
在早期的问题" Java是否通过引用传递? "中,有关Java如何传递变量的扩展讨论.Java确实按值传递对象引用.
在您的代码中,将传递数组(对象)的引用calculate()
.这些参考值传递的,这意味着到的值进行任何更改b
,并c
仅在该方法中可见(他们真的只是一个副本s_ccc
和t_ccc
).这就是为什么t_ccc
在main()
从来没有受到影响.
为了强化这个概念,一些程序员将方法参数声明为final
变量:
public static void calculate(final int[] b, final int[] c)
现在,编译器甚至不允许您更改b
或的值c
.当然,这样做的缺点是你不能再在方法中方便地操作它们.
这是一种理解它的简单方法.
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
.调用使用对该数组的复制引用(in )calculate
更改了引用的数组的内容.s_ccc
b
局部变量c
开始作为一个副本t_ccc
,并操纵之内calculate
,但没有改变t_ccc
自己,也不它引用的数据.
该方法按值接收变量.这些值不能更改(只要方法的调用者看到),但它们中包含的值可以(如果它是一个对象,或者在这种情况下是一个数组).
因此,当您更改数组中的值b [0]时,可以在方法外部看到更改.但行
c = b;
将更改方法内部的c值,但在方法外部不会看到该更改,因为c的值是按值传递的.
该行calculate(s_ccc, s_ccc);
表示您实际上没有对t_ccc做任何事情.但是,如果此行读取calculate(s_ccc, t_ccc);
的效果仍然相同.
这是因为您在此处为c c = b;
分配了一个新值:当为引用参数赋值时,引用将丢失.
这是通过引用变量更改和分配新值之间的区别.