按值和引用传递数组
这些是来自ac#book的例子,我正在阅读这个示例实际上正在做的一点点麻烦,想要一个解释来帮助我进一步了解这里发生的事情。
//creates and initialzes firstArray int[] firstArray = { 1, 2, 3 }; //Copy the reference in variable firstArray and assign it to firstarraycopy int[] firstArrayCopy = firstArray; Console.WriteLine("Test passing firstArray reference by value"); Console.Write("\nContents of firstArray " + "Before calling FirstDouble:\n\t"); //display contents of firstArray with forloop using counter for (int i = 0; i < firstArray.Length; i++) Console.Write("{0} ", firstArray[i]); //pass variable firstArray by value to FirstDouble FirstDouble(firstArray); Console.Write("\n\nContents of firstArray after " + "calling FirstDouble\n\t"); //display contents of firstArray for (int i = 0; i < firstArray.Length; i++) Console.Write("{0} ", firstArray[i]); // test whether reference was changed by FirstDouble if (firstArray == firstArrayCopy) Console.WriteLine( "\n\nThe references refer to the same array"); else Console.WriteLine( "\n\nThe references refer to different arrays"); //method firstdouble with a parameter array public static void FirstDouble(int[] array) { //double each elements value for (int i = 0; i < array.Length; i++) array[i] *= 2; //create new object and assign its reference to array array = new int[] { 11, 12, 13 };
基本上有代码我想知道的是,本书是说如果数组是通过值传递的,而不是原始调用者没有被方法修改(根据我的理解)。 因此,在方法FirstDouble的末尾,他们尝试将局部变量数组分配给一组失败的新元素,并且显示原始调用者的新值为2,4,6。
现在我的困惑是如何通过值传递方法FirstDouble中的for循环如何将原始调用者firstArray修改为2,4,6。 我认为价值应该保持在1,2,3。
提前致谢
理解这一点的关键是要知道值类型和引用类型之间的区别。
例如,考虑一个典型的值类型int
。
int a = 1; int b = a; a++;
执行此代码后, a
的值为2, b
的值为1
。 因为int
是值类型,所以b = a
获取a的值的副本。
现在考虑一个类:
MyClass a = new MyClass(); a.MyProperty = 1; MyClass b = a; a.MyProperty = 2;
因为类是引用类型,所以b = a
仅指定引用而不是值。 所以b
和a
都指的是同一个对象。 因此,在执行a.MyProperty = 2
之后, b.MyProperty == 2
因为a
和b
引用相同的对象。
考虑到你的问题中的代码,数组是一个引用类型,所以对于这个函数:
public static void FirstDouble(int[] array)
变量array
实际上是一个引用,因为int[]
是一个引用类型。 所以array
是一个按值传递的引用 。
因此,对函数内部的array
所做的修改实际上应用于array
引用的int[]
对象。 因此,对于引用同一对象的所有引用,这些修改都是可见的。 这包括调用者持有的引用。
现在,如果我们看一下这个函数的实现:
public static void FirstDouble(int[] array) { //double each elements value for (int i = 0; i < array.Length; i++) array[i] *= 2; //create new object and assign its reference to array array = new int[] { 11, 12, 13 }; }
还有一个复杂因素。 for
循环只是将传递给函数的int[]
每个元素加倍。 这是调用者看到的修改。 第二部分是将新的int[]
对象赋值给局部变量array
。 这对调用者是不可见的,因为它所做的就是更改引用array
的目标。 并且由于引用array
是按值传递的,因此调用者不会看到该新对象。
如果函数声明如下:
public static void FirstDouble(ref int[] array)
那么引用array
将通过引用传递,并且调用者将在函数返回时看到新创建的对象{ 11, 12, 13 }
。
除非您特别看到ref
或out
否则所有方法参数都按值传递。
数组是引用类型。 这意味着您按值传递引用。
只有在为其分配新数组时才会更改引用本身,这就是为什么这些赋值不会反映在调用者中的原因。 当您取消引用对象(此处的数组)并修改基础值时,您不会更改变量,只是指向它。 即使变量(即它指向的变量)保持不变,调用者也会“看到”这种变化。
多么令人困惑的用语!
澄清,
1)对于方法foo(int [] myArray),“按值传递引用(对象)”实际上意味着“传递对象地址(引用)的副本”。 这个’副本’的价值,即。 myArray,最初是原始对象的Address(引用),意味着它指向原始对象。 因此,myArray指向的内容的任何更改都将影响原始对象的内容。
但是,由于myArray本身的’value’是副本,因此对此’value’的任何更改都不会影响原始对象及其内容。
2)对于方法foo(ref int [] refArray),“通过引用传递引用(对象)”意味着“传递对象的地址(引用)本身(不是副本)”。 这意味着refArray实际上是对象本身的原始地址,而不是副本。 因此,对refArray的’value’或refArray指向的内容的任何更改都是对原始对象本身的直接更改。