C#中string类型赋值问题
⼤家都知道,C#中的string是⼀个引⽤类型,String对象是存放在堆上,⽽不是堆栈上的,因此,当把⼀个字符串变量赋给另⼀个字符串时,会得到对内存中同⼀个字符串的两个引⽤。但是⼤家有没有想过,为什么修改其中⼀个字符串,另外⼀个不受影响呢?
原来,当我们把⼀个字符串变量赋给另⼀个字符串时,就会创建⼀个全新的String对象,就是说这个时候就会有两个对象,⽐如:class StringExc
{
public static void Main()
{
string s1 = "original string";
string s2 = s1; //注意此时会创建⼀个新对象
Console.WriteLine( "s1 is " + s1 );
Console.WriteLine( "s2 is " + s2 );
s1 = "changed string";
Console.WriteLine( "s1 is now " + s1 );
Console.WriteLine( "s2 is now " + s2 );
}
}
输出结果为:
s1 is original string
s2 is original string
s1 is now changed string
s2 is now original string
也就是说,改变s1的值并没有对s2造成任何影响,这与我们平时所说的引⽤类型的⾏为正好相反。当⽤值"original string"初始化s1时,就在堆上分配了⼀个String对象。在初始化s2时,引⽤也指向这个对象,所以s2的值也是"original string"。但是现在要改变s1的值,⽽不是替换原来的值时,堆上就会为新值分配⼀个新对象。s2变量仍然指向原来的对象,所以它的值没有改变。
另外,如果我们像下⾯这样:
string str1 = "abc";
writeline输出数值变量string str2 = "abc";
当我们⽤System.Object.Equals(str1,str2)⽐较时,返回值是true;按理说str1和str2应该指向不同的空间,应该返回false才对啊。原来Equals有三个版本:
public override bool Equals(object);
public bool Equals(string);
public static bool Equals(string, string);
前两个实例⽅法内部会调⽤CompareOrdinal静态⽅法,它会字符串中的各个字符,如果相等就返回true。第三个⾸先会检查两个引⽤指向的是否是同⼀个对象,如果是,就返回true,不再去⽐较各个字符了。
其实CLR使⽤了⼀种叫字符串驻留的技术,对于
string str1="abc";
string str2="abc";
当CLR初始化时,会创建⼀个内部的散列表,其中的键为字符串,值为指向托管堆中字符串的引⽤。刚开始,散列表为空,JIT编译器编译⽅法时,会在散列表中查每⼀个⽂本常量字符串,⾸先会查"abc"字符串,并且因为没有到,编译器会在托管堆中构造⼀个新的指向"abc"的String对象引⽤,然后将"abc"字符串和指向该对象的引⽤添加到散列表中。
接着,在散列表中查第⼆个"abc",这⼀次由于到了该字符串,所以编译器不会执⾏任何操作,代码中再没有其它的⽂本常量字符串,编译器的任务完成,代码开始执⾏。执⾏时,CLR发现第⼀个语句需要⼀个"abc"字符串引⽤,于是,CLR会在内部的散列表中查"abc",并且会到,这样指向先前创建的String对象的引⽤就被保存在变量s1中,执⾏第⼆条语句时,CLR会再⼀次在散列表中查"abc",并且仍然会到,指向同⼀个String对象的引⽤会被保存在变量s2中,到此s1和s2指向了同⼀个引⽤,所以
System.Object.Equals(s1,s2)就会返回true了。
另外,C#中是不允许⽤new操作符创建String对象的,编译器会报错。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论