zoukankan      html  css  js  c++  java
  • 到底什么是字符串的不变性?

    string 类型是c#中使用最频繁的类型,因此CLR用专门的方法来处理、优化string,使得string虽然你是引用类型,但在表现上被.NET优化为值类型。

    先看string的定义是:

      public sealed class String : IComparable, ICloneable, IConvertible, IComparable<string>, IEnumerable<char>, IEnumerable, IEquatable<string>

    从这里我们可以得知:

    string的本质是字符集合,因此,linq to object 的操作能作用在string上。

    string是sealed,该特性是为字符串不变性(恒等性,immutability)和字符串驻留机制提供有效保证。(子类无法继承,因此无法破坏CLR对string的特殊处理机制)

    这个特性的表现是,当对实例使用:

    Insert(),PadLeft(),Remove(),Replace(),SubString(),ToUpper(),ToLower(),Trim()

    等方法时,原有的字符串仍然在内存中,不被改变,对实例操作的结果需要在内存中创建新的字符串对象。

    这样做的好处:

    1)保证原string对象的稳定性。

    2)string不会出现线程同步问题。

    这样做的坏处:

    性能和内存的双重。

    为了应对这个缺点,CLR使用了哈希表类型的暂存池。

     哈希表的key是string,value则是存储托管堆中的地址。当JIT编译方法时,会首先在哈希表中查找每一个字符串常量,如果找不到,则在表中创建一个键值对;如果找到,则将找到的键值对的value值赋给这个对象。

    例子:

                string strA = "abc";
                string strB = "abc";
                bool b=ReferenceEquals(strA, strB);//True

    这边名strA和strB指向的是同一个地址。

    两个方法

    IsInterned和Intern

    根据MSDN对IsInterned的描述:

    此方法在暂存池中查找 str。 如果已经将 str 放入暂存池中,则返回对此实例的引用;否则返回 null

    例子:

                string s1="abc";    
                string s2=string.IsInterned(s1);
                Console.WriteLine(s2);//"abc"

     很奇怪的一点是:

     string s1=string.IsInterned("def");
                Console.WriteLine(s1); //"def"

    预料中结果是null,因为"def"此时并不在暂存表中。结果打印出了"def"。猜测可能是当写"def"时,暂存池中已经将其加入了。

                string s1 = "abc";
                string s2 = s1+ "def";
                string s3 = string.IsInterned(s2);
                Console.WriteLine(s3);   //null
                string s4 = "abcdef";
                string s1 = "abc";
                string s2 = s1+ "def";
                string s3 = string.IsInterned(s2);
                Console.WriteLine(s3); //"abcdef"

    而Intern的意思相似:

    如果暂存了 str,则返回系统对其的引用;否则返回对值为 str 的字符串的新引用。

    区别是:Intern如果在暂存池中查找不到该str时,则将该str添加到暂存池中,而IsInterned则不添加。

    例子:

                string strA = "abcdef";
                string strB = "abc";
                string strC = strB + "def";
                var b1 = ReferenceEquals(strA, strC); //False,因为strC是动态构造的,因此这样的字符串不会被添加到暂存池中维护
                strC = string.Intern(strC);  //由于strC不在暂存池中,则将其添加进去。
                var b2 = ReferenceEquals(strA, strC);  //True 

    *本文依据《你必须知道的.NET》一书总结

  • 相关阅读:
    数据导入
    数据库导入导出命令
    题库
    struts2的配置文件简洁
    修改oralce11g 字符集为ZHS16GBK
    Linux上安装JDK+Tomcat
    Android中adb的使用
    【转】Android获取IP的方法,并可以判断手机是否联网
    Android中R.java没有自动生成问题
    Android中SQLiteOpenHelper的理解
  • 原文地址:https://www.cnblogs.com/Benjamin/p/3338474.html
Copyright © 2011-2022 走看看