string hehe = "hehe";
string haha = "haha";
haha = hehe;
Console.Write (hehe);
Console.WriteLine(haha);
//输出:hehehehe
hehe = "改了";
Console.Write (hehe);
Console.WriteLine(haha);
//输出:改了hehe
//string 类型不是一个引用类型吗?
//既然是引用类型,那么在haha = hehe;之后haha与hehe应该是指向堆中的同一个地方
//我感觉haha应该随着hehe的改变而改变
//可是最后结果却不是这样
//谁懂的过来解释一下,谢谢大家,祝大家清明节之后发大财
Console.ReadKey();
string haha = "haha";
haha = hehe;
Console.Write (hehe);
Console.WriteLine(haha);
//输出:hehehehe
hehe = "改了";
Console.Write (hehe);
Console.WriteLine(haha);
//输出:改了hehe
//string 类型不是一个引用类型吗?
//既然是引用类型,那么在haha = hehe;之后haha与hehe应该是指向堆中的同一个地方
//我感觉haha应该随着hehe的改变而改变
//可是最后结果却不是这样
//谁懂的过来解释一下,谢谢大家,祝大家清明节之后发大财
Console.ReadKey();
hehe = "改了";
之后,hehe指向另外一个位置。这里的引用,类似于C/C++中的指针,然而却不同于指针,比如在这里,如果你把引用想象为指针的话,就会妨碍你对这个问题的正确理解。
但是根据我们的内存分析可知, string在本质上还是一个引用类型,在参数传递时发生的还是按址传递,不过由于其特殊的恒定特性,在函数内部新建了一个string对象并完成初始化,但是函数外部取不到这个变化的结果,因此对外表现的特性就类似于按值传递。
hehe和haha都指向同一个字符串,即"hehe";但是,hehe和haha并没有互相应用的关系。只是"碰巧"它们都指向同一个字符串。执行 hehe = "改了" 这行后hehe就指向了新的字符串,而haha还是指向旧的内容。
.Net规定string是不可变(immutable)的,所以最开始的hehe和haha都指向同一个字符串,这样可以节省第二个拷贝,节省内存。
你可以发现string类并不提供修改的功能。象string1.Replace(...)并不修改string1,而是将结果以新string的形式返回。
象string1[0]可以返回第一个字符,但是你不能修改string1[0]。题外话:如果你能够直接篡改hehe指向的内容,那么haha将体现改动(记得最开始它们指向同一字符串)。
把hehe = "改了"换成以下代码:unsafe
{
fixed (char* ptr = hehe)
{
ptr[0] = 'j';
}
}...
Console.WriteLine(haha); // output jeha
记得编译项目选型要允许unsafe。
hehe 和haha两个名字只是引用变量而已,类似指针。它们指向string池中的实际string对象“hehe”。但当你hehe = "改了"时,只是让hehe指向了另一个string实例,并没有去修改原来的“hehe”所以结果就是这样了。