(ZT)咋这么多怪事啊?——String是引用类型吗?

(ZT)咋这么多怪事啊?——String是引用类型吗?

一,
string是引用类型,那么比较两个实例应当是地址才是啊
string s="hello";
string t="hello";
s,t不应当相等啊
二,
Console.WriteLine((object)1 == (object)1);//结果为false
Console.WriteLine((object)"ok" == (object)"ok");//结果为true
为什么?装箱值代表什么?
三,
string a = "hello",b=string.Copy(a),c = "hello" ;
Console.WriteLine((object)a == (object)b);//false
Console.WriteLine((object)a == (object)c);//true
为什么?
四,
string s,t;
s="ok";
t=s;
s="yes";//改变s并不会同时改变t
这好像不符合引用类型的惯例吧?(跟值类型到是差不多)
为什么string是不可改变的?
string的定义跟其它类有什么不同吗?(例如StringBuild,不要把string的定义贴出来,说出原因就行了)
其它的类,如果两个对象引用同一实例,改变之一,另一个也会变啊

【lovingkiss】:
一,
string是引用类型,那么比较两个实例应当是地址才是啊
string s="hello";
string t="hello";

string是特殊的引用类型~~——特殊情况特殊处理

【fengyunluanwu】:
MARK


【lovingkiss】:
关于string是值类型还是引用类型 
当然了,string本质上肯定是引用类型,但是这个特殊的类却表现出值类型的特点:
判断相等性时,是按照内容来判断的,而不是地址
它肯定是一个引用类型没错,两个方面来看:

1. class string继承自object,而不是System.ValueType(Int32这样的则是继承于System.ValueType)
2. string本质上是个char[],而Array是引用类型,并且初始化时也是在托管堆分配内存的
微软设计这个类的时候估计是为了方便操作,所以重写了操作符和Equals方法,不然的话我们判断string相等得这样:
foreach(char c in s.ToCharArray()){...}
但是另外一个常用的对象微软却没有帮忙重写等值判断的方法:Array
这样int[] a = {1,2,3}和int b = {1,2,3},a == b?// false

还有一个容易搞错的地方是按引用传递还是按值传递的问题:
引用类型按引用传递,值类型按值传递,这些都不错。
一个引用类型,比如System.Array类,作为参数向一个方法传递时,传送的是指针,但是这两种代码是不是就意味着等效?
void Test(Array a)和void Test(ref Array a)
结果是并不完全等效。
如果在函数内部调用构造函数新建了对象并赋予参数,则函数外的变量不会受影响;
比如a = new ...
如果只是改动该参数(一个对象)的字段,则会有影响,此时加不加ref都是等效的。
比如a[i] = ...
而string类型的另外一个特殊性在于它是“不会变”的,每次操作string,都相当于新建了一个string对象,所以对于string来讲,void Test(String s)和void Test(ref String s)永远都是不一样的。在这里string再次表现出了值类型的特点,我们以为这是传值 - 实际上传送的还是地址,但是在操作的时候string被再次初始化,外部根本不能得到这个变化。
对于变量作用域的概念来讲,微软这么设计也是合理的:既然是函数内部建立的对象,外部就应该没有访问这个对象的能力,函数结束后,这些对象就会被GC收集,同样不会影响外面的程序。
----------
update on [23, August]
string可以看作是char[]的包装但是实际上CLR并不是用托管的char[]来实现的:
这里是关于string的索引器的代码:
public char this[int index]
{
      get
      {
            return this.InternalGetChar(index);
      }
}
而InternalGetChar函数则是:
[MethodImpl(MethodImplOptions.InternalCall)]
internal char InternalGetChar(int index);
这里可以看到string的确是内部调用CLR方法实现的,而不是char[]的包装


【lovingkiss】:
三、
        Dim S As String, B As String
        S = "Abcd"
        B = String.Copy(S)
        If S = B Then
            MsgBox("相等") '提示相等
        Else
            MsgBox("不相等")
        End If
我看不懂C#,是不是你最后转成了Object??

【lovingkiss】:
四、String确实是带有值类型特性的引用类型,似乎不需要理由吧?
难道真的需要理由??——难道非要问微软为啥这么做??
你可以考虑问问微软为啥要为了方便——把String弄得不伦不类的

【lizhizhe2000】:
1.String对一些操作符进行了重载
2.String是一个不可变对象,因此才出现了StringBuilder类,楼上的兄弟讲述已经很明白了!

【amandag】:
这么早就起来学习,表扬先...


一,
string是引用类型,那么比较两个实例应当是地址才是啊
string s="hello";
string t="hello";
s,t不应当相等啊
==============================================
每个字符串都是一个字符串对象,但.NET有个字符串池的概念,如果用到了同样的字符串,会从字符串池中进行查找,而不是再new出来一个字符串。(如果你查看IL的指令,你会发现并没有newobj指令,而是一个特殊的IL指令 加载字符串),这是因为CLR有一个更为特殊的、高效的构造字符串对象的方式
所以,"hello"在堆里只有一个,而s和t都是指向这个字符串的引用,它们当然是相等的

二,
Console.WriteLine((object)1 == (object)1);//结果为false
Console.WriteLine((object)"ok" == (object)"ok");//结果为true
为什么?装箱值代表什么?
========================================================
这个问题和上一个问题类似..左边和右边的(object)1装箱后在堆里都有自己的一个新地址,但字符串不是这样地


三,
string a = "hello",b=string.Copy(a),c = "hello" ;
Console.WriteLine((object)a == (object)b);//false
Console.WriteLine((object)a == (object)c);//true
==================================================================
还是和第一个类似,只有Copy的那一个堆里有新的地址

四,
string s,t;
s="ok";
t=s;
s="yes";//改变s并不会同时改变t
这好像不符合引用类型的惯例吧?(跟值类型到是差不多)
为什么string是不可改变的?
string的定义跟其它类有什么不同吗?(例如StringBuild,不要把string的定义贴出来,说出原因就行了)
其它的类,如果两个对象引用同一实例,改变之一,另一个也会变啊
================================================================
string虽然是引用类型,但确实有些值类型的样子,不能更改的原因的细节,
1. 我们可以在一个字符串上进行各种操作,但字符串并不改变
2. 操作字符串的时候不会出现线程同步的问题

但是这种性能的提升和直接访问特性的代价是,string必须为sealed类型。因为CLR不希望我们添加自己的字段去破坏它。

如果你还是不了解,我很建议你参考一下.NET框架程序设计这本书

【Bote_China】:
一、尽管 string 是引用类型,但相等运算符(== 和 !=)被定义为比较 string 对象(而不是引用)的“值”
二、(object)1 == (object)1输出 False,这是因为int为值类型,预定义的引用类型相等运算符对值类型没有意义。强制转换创建对已装箱 int 值的两个单独实例的引用。
三、变量 a和 b引用两个包含相同字符的不同 string 实例。



【lovingkiss】:
amandag(高歌) 的说法我表示怀疑

如果s和t都是指向这个字符串的引用,它们当然是相等的——但是假如这时候我改变S的内容,就相当于我改变了他引用的空间??然后我再改变t,t的空间也变化?没有变量使用的字符串缓冲就被回收了?

呵呵,这个我没有理论依据,不过是感觉
1、String的比较,是微软特殊提供的,比较内容,而不是地址。——这点是肯定的
2、字符串空间的存放,应该取决于变量声明吧?应该是声明的时候就已经定义出来空间了阿。——这点是感觉,否则我频繁的变化某个字符串的时候,岂不是每次都要改变变量所在的空间??






【lovingkiss】:
string s="helloabc";
string t="hello";

如果字符串缓冲的话,是不是s空间还要包括t空间阿?~~呵呵~~

【lovingkiss】:
string类型的另外一个特殊性在于它是“不会变”的,每次操作string,都相当于新建了一个string对象,所以对于string来讲,void Test(String s)和void Test(ref String s)永远都是不一样的

【twtqing】:
楼上的人都是高人 学习

【JustLovePro】:
mark

【wzd24】:
同意高歌的。

Desire has no rest.
原文地址:https://www.cnblogs.com/samcn/p/1297998.html