C# 数组为引用还是值类型?若是引用类型,下边该怎样理解?

private static void change(int[] n)
{
n[2] = 1000;
}
private static void change2(int[] n)
{
n = new int[1] { 3 };
}
public static void Main(String[] args)
{
int[] n = new int[] { 1, 2, 3, 4 };
change(n);
Console.WriteLine(n[2].ToString());//1000 ==》引用类型
Console.WriteLine("**************************");
int[] n2 = new int[] { 1, 2, 3, 4, 5 };
change2(n2);
for (int j = 0; j < n2.Length; j++)
{
Console.Write(n2[j]);//1, 2, 3, 4,5 ==》如果是引用类型这里所得的值为什么不只为 3
}
Console.ReadKey();
}

当运行change2方法时,n2的数组对应的内存地址重新分配一个新的只有一个元素的新的地址空间,但是由于n2新的地址空间的作用域仅限于chang2的方法中,当方法调用结束作用域结束,会自动释放刚刚分配的地址空间,但是n2的对象作用域是在主函数里面的,在chang2调用结束后由于主函数中的n2在内存中的原有地址一直存在,n2会重新指向原有内存地址,所以循环出的结果是12345。
如果把chang2的方法改成
private static int [] change2(int[] n) { n = new int[1] { 3 }; return n; }这样n2的结果就会变成3,写的有点罗嗦,逻辑不是很明确,但是意思表达出来了。追问

谢谢你,耐心仔细的回答,现在明白了!

温馨提示:内容为网友见解,仅供参考
第1个回答  2013-11-26
这确实是比较难以理解的现象,网上查了一下,说什么堆之类的规则,总的来说就是数组内元素为引用,数组本身不是(似乎有点牵强。。。)。如果你在函数和调用处都加上ref就是完全的对象引用。
参考资料:
http://stackoverflow.com/questions/967402/are-arrays-or-lists-passed-by-default-by-reference-in-c本回答被提问者采纳
第2个回答  2021-02-01
change2(n)的参数n引用n2的值(n指向n2),当n=new的时候,n就指向了new的实例,就和n2脱离关系了,n2还是原来的n2,n是新new的数组。
如果你学过指针,可以理解为n的指针指向n2,n=New之后,n的指针指向新实例
第3个回答  2013-11-26
也许可以这样理解,数组是值类型,但是他的值是地址,所以你的change(n)函数改变的是数组地址中的内容,这个是合理的。而change2(n2)则是对地址进行赋值,而数组是值类型,所以没有变化。追问

谢谢,现在明白了!

第4个回答  2020-02-12

首先明确,数组是引用类型,以它为参数时按引用传递。下来我们来跟踪一下在运行各步骤中变量的内存地址变化情况就一目了然了。

    main方法中

    int[] n2 = new int[] { 1, 2, 3, 4, 5 };
    这里会分配一个新的内存指针给变量n2,我们假设它指向地址(0x000002725DFDABA0)

    当继续执行到刚刚进入到change2方法中时,该方法体内变量n的内存指针就被指向上一步中的地址(0x000002725DFDABA0),也就是按引用传递了。

    当执行change2方法中的n = new int[1] { 3 };后,操作系统会在堆内存中开辟新内存以便存放new出来的新对象,同时变量n内存指针值被从前面的值重置为新开辟的内存地值,我们假定它为(0x000002725DFDAC10)。让我们迷惑的玄机就在这里,n这个指针 它的值发生了变化,而这和n2无关。

    再下来就是跳出change2方法体后回到main方法中了,可想而知n2还指向原来的内存地址(0x000002725DFDABA0),所以它的值当然还是原来的 int[] { 1, 2, 3, 4, 5 }了。而对于变量n,它会超出变量作用域指针也就不存在了,在合适的时机int[1] { 3 }所占用的堆内存就会被GC安全回收。

    总结,我们也可以更深刻的理解一下,所谓引用类型,它是一个内存地址,换个说法它就是一个指针,这个指针指向堆内存里真正存放引用类型的元数据的地方。只要做new操作 那么就会开辟新的内存地址,当不再有指针指向那些开辟的内存地址时,它们就成为GC回收的目标。

相似回答