string不完全手册

2022-11-22,,

string 引用类型,,还是值类型 ??

首先string类型肯定是引用类型,应为它自己继承自object类型,,由于它的特殊性,它有表现了一些值类型的特点. 比如 重载了==, 比较两个字符串的内容,而不是地址

为什么不将string设置成值类型呢?
我的理解是:
string经常要被多个地方用到,如果每个对象保存String的一份Copy,则会消耗大量内存, 而且我们使用string是只关心它的内容,不关心此对象,因此每个对象保存一个它的Copy是没有意义的.

为什么string很多时候表现出值类型的特点呢?
我的理解是: 
1. 重写 equal, 那是因为我们不关心string变量的地址,只关心它的值.
2. string设计成不变性

为什么string具有不变性呢?
我的理解是:
1.不可改变的一个优点是它是线程安全的。
2.再者string是最常用来作为集合(Map,Hashtable) 键值得类型,而一旦一个String对象被用作集合的键值,改变String的内容就会破坏集合的语义,造成程序错误。
3.如果多个string对象引用同一个地址,当其中的某个对象改变时,使得此改变不会影响到其他对象,否则系统很容易rush.
4.我们一般只关系string的值 

String作为参数传递的是什么?
按地址传递,而非值传递.

public static string staticString = string.Empty;
static void Main()
        }

理由:  引用类型按引用传递,值类型按值传递,这些都不错。  【这里表达是有误,引用类型传递的应该是此变量的值,只不过这个变量保存的是引用类型的地址,这是个Pointer,这个不算是引用传递,也叫值传递。 在函数里面拷贝了一份变量的值,指向的仍然是这个引用类型的地址】 [修改于2007年10月24日]
一个引用类型,比如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收集,同样不会影响外面的程序。

 字符串驻留:

如果内存上保留多个”Hello”实例,对内存是种浪费.如果在内存中只存储一个”Hello”字符串,并且所有对”Hello”字符串的引用都指向该字符串对象,就会提供内存效率.

String s = “hello”;
Object.ReferenceEquals(“hello”, s));    // true;

CLR初始化时,它会创建一个内部散列表,其中键为字符串,值为指向托管堆中字符串对象的引用.JIT编译时,它会在散列表中查找每一个文本常量字符串.

如果我们动态创建字符串呢?
 
   string s1 = "Hello";   
    
string s2 = "Hel";  
    
string s3 = s2 + "lo";
   
string s5 = "Hel" + "lo";      
    
string s4 = string.Intern(s2 + "lo");
   
Console.WriteLine(object.ReferenceEquals(s1, s3));              //output: False
   
Console.WriteLine(s1.Equals(s3));                               //output: True
   
Console.WriteLine(object.ReferenceEquals(s1, s4));              //output: True
   
Console.WriteLine(object.ReferenceEquals(s1, s5));              //output: True

 因为s3是被动态创建的它并没有添加到CLR内部散列表中.
垃圾回收器不会释放CLR内部的散列表中引用的字符串对象,只有当整个进程中所有的应用程序域都不再引用这个字符串时,它们才被释放.

通过字符表达式计算出表达式结果:

        }