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();
}
谢谢你,耐心仔细的回答,现在明白了!
谢谢,现在明白了!
首先明确,数组是引用类型,以它为参数时按引用传递。下来我们来跟踪一下在运行各步骤中变量的内存地址变化情况就一目了然了。
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回收的目标。