MSDN 中明确指出 String 是引用类型而不是值类型,但 String 表面上用起来却像是值类型,这又是什么原因呢?
首先从下面这个例子入手:
-
//值类型
-
int a = 1;
-
int b = a;
-
a = 2;
-
Console.WriteLine("a is {0},b is {1}", a, b);
-
-
//引用类型
-
string str1 = "ab";
-
string str2 = str1;
-
str1 = "abc";
-
Console.WriteLine("str1 is {0},str2 is {1}", str1, str2);
-
Console.Read();
输出结果:
-
//结果:
-
//a is 2,b is 1
-
//str1 is abc,str2 is ab
- 1
- 2
- 3
从运行结果可以看出:str2 的值还是 ab ,并没有随着 str1 值的改变而改变。如果string是引用类型,按理Str1和Str指针都指向同一内存地址,如果Str的内容发生改变,Str1应该也会相应变化。此例子,看着string更像是值类型。 但是MSDN却说String是引用类型。究其原因,是因为string对象是不可变的,包括长度和其中任何字符都是不可以改变的。
String的不变性
string 对象称为不可变的(只读),因为一旦创建了该对象,就不能修改该对象的值。有的时候看来似乎修改了,实际是string经过了特殊处理,每次改变值时都会建立一个新的string对象,变量会指向这个新的对象,而原来的还是指向原来的对象,所以不会改变。这也是string效率低下的原因。如果经常改变string的值则应该使用StringBuilder而不使用string。
在例子中str1=”ab”,这时在内存中就将“ab”存下来,如果再创建字符串对象,其值也等于“ab”,str2=”ab”,则并非再重新分配内存空间,而是将之前保存的“ab”的地址赋给str2的引用,这就能印证例子2中的结果。而当str1=”abc”其值发生改变时,这时检查内存,发现不存在此字符串,则重新分配内存空间,存储“abc”,并将其地址赋给str1,而str2依然指向“ab”的地址。可以印证例子中的结果。
结论
String是引用类型,只是编译器对其做了特殊处理。