参考下面的代码:
int i = 0;
Console.WriteLine(Object.ReferenceEquals(i, i));
Console.WriteLine(i.Equals(i));
Console.WriteLine(i.GetType().IsValueType);
string s1 = "String1";
string s2 = "String1";
Console.WriteLine("s1 = s2: {0}", Object.ReferenceEquals(s1, s2));
Console.WriteLine("{0} interned: {1}", s1,
string.IsNullOrEmpty(string.IsInterned(s1)) ? "No" : "Yes");
string suffix = "A";
string s3 = "String" + suffix;
string s4 = "String" + suffix;
Console.WriteLine("s3 = s4: {0}", Object.ReferenceEquals(s3, s4));
Console.WriteLine("{0} interned: {1}", s3,
String.IsNullOrEmpty(String.IsInterned(s3)) ? "No" : "Yes");
执行结果如下:
False
True
True
s1 = s2: True
String1 interned: Yes
s3 = s4: False
StringA interned: No
比较值类型时。 如果 objA
和 objB
是值类型,则在将其传递到 ReferenceEquals 方法之前,会将这些值装箱。 这意味着,如果 objA
和 objB
表示值类型的同一个实例,则 ReferenceEquals 方法仍返回 false。比如上面的Object.ReferenceEquals(i, i)操作。
c#像java一样也存在一个常量池,上面的代码“String1”这个字符串会被直接放到常量池里面,按照c#的说法是暂存,以便下次使用,这是一种优化方式。所以s1和s2会指向同一个引用,但是s3和s4则不是指向一个常量,而是一个表达式,那么也就不存在暂存的情况了,所以s3和s4不指向同一个引用。
另外提一点,string类型是引用类型,不是值类型,只不过它的=号被重写了,导致它每次调用=号的时候,都会引发深拷贝。