问题:
private static void change(int[] m)
{
m = new int[1] { 10 };
}
public static void Main(String[] args)
{
int[] n = new int[] { 1, 2, 3, 4, 5 };
change(n);
for (int j = 0; j < n.Length; j++)
{
Console.Write(n[j]);
//实际输出结果是:1, 2, 3, 4,5 如果是引用类型这里为什么不是输出 10
}
Console.ReadKey();
}
我是这样理解的:
首先给自己明确,数组是引用类型,以它为参数时按引用传递。下来来跟踪一下问题代码在运行各步骤中变量的内存地址变化情况
-
main方法中
int[] n = new int[] { 1, 2, 3, 4, 5 };这里会分配一个新的内存指针给变量n,我们假设它指向地址(0x000002725DFDABA0)
-
当继续执行到刚刚进入到change方法中时,该方法体内变量n的内存指针就被指向上一步中的地址(0x000002725DFDABA0),也就是按引用传递了,这里还是没有鬼的。
-
当执行change方法中的m = new int[1] { 10 };后,操作系统会在堆内存中开辟新内存以便存放new出来的新对象,同时变量m内存指针值被从前面的值重置为新开辟的内存地值,我们假定它为(0x000002725DFDAC10)。让我迷惑的玄机就在这里,m这个指针 它的值发生了变化,而n则还是原来的指针值,特别要注意这里m和n不再指向同一块内存。
-
再下来就是跳出change方法体后回到main方法中了,可想而知n还指向原来的内存地址(0x000002725DFDABA0),所以它的值当然还是原来的 int[] { 1, 2, 3, 4, 5 }了。而对于变量m,它会超出变量作用域指针也就不存在了,在合适的时机int[1] { 10 }所占用的堆内存就会被GC安全回收。
-
总结,我们也可以更深刻的理解一下,所谓引用类型的变量,它本质是一个指向某块内存地址的指针,怎么指向的?其实仅仅是它本身保存了另一块存放实际数据的内存的地址,这个指针指向堆内存里真正存放引用类型的元数据的地方。
-
只要对引用类型做new操作 那么就会在堆内存里开辟新的内存地址,当不再有指针指向那些开辟的内存地址时,它们就成为GC回收的目标。方法调用时参数的传递对于引用类型而言它的传递过程是实参把它自己的指针赋值给了形参,但是要注意思考实参和形参是两个不同的指针只是他们指向相同,它们有各自的作用域。
如果有理解的不正确的地方,请路过的高手不吝指正。