String - 兴趣解读

1、概述html

String是咱们日常用得最多的基元类型之一,虽然咱们常用并且感到很是熟悉;但不少朋友只知道一个字符串的定义、使用或知道如何使用StringBuilder来达到高效构建字符串,可是有多少朋友有兴趣去了解背后的一些不为咱们知道的秘密算法

2、为何把String加入到基元类型中函数

在之前的面向过程语言中,并无String这个类型,定义一个字符串的方式则采用一个Char[],虽然提供了对字符串的操做、比较等函数,可是仍是不够方便也不太符合面向对象作法,因此在面向对象语言中,string也加入了基元类型的队列中;布局

3、String核心特征immutable(不可变)性能

表明一个不可变的顺序字符集,也就是说一经建立,字符串编不能以任何方式进行修改;具备如下3个优势:ui

1.     容许在一个字符串上执行各类操做,而不实际地更改字符串;spa

2.     在操做或访问一个字符串的时候不会发生线程同步的问题;线程

3.     基于性能的考虑,String类型与CLR紧密集成,CLR知道String类型中定义的字段如何布局,并且CLR会直接访问,因此开发的时只好将String定义为密封类(Sealed);指针

4、被重写的两个方法GetHashCodeEqualscode

1.     GetHashCode方法进行了重写,目的是为了知足两个字符串的判断;

2.     Equals方法进行重写,其中Equals方法最终仍是调用了GetHashCode方法来进行判断;

5、“==”、EqualsCompare,字符串判断到底用哪一个好点?

1.     String对“==”操做符进行重载,内部实现进行了空值判断后,再调用Equals进行判断(因此采用"=="操做符,不会抛出空指针异常)

2.     StringEquals方法,由于调用Equals方法的时候,直接经过返回HashCode进行比较,效率最高,有可能对象为空,有可能会抛空指针异常,因此用的时候须要留意;

3.     StringCompare方法:该方法是一个静态方法,内部实现是首先判断字符串的长度是否相等,若是长度不相等,直接返回结果,若是长度相等,则会采用逐个字符进行判断,若是方法中的CultureInfo不为空,则判断的过程当中会逐个字符进行展开(这里涉及到语言的问题,若是采用德语会把"β"展开为"ss",因此”strasse”staβe的判断结果是相同的); 

注:若是通常状况下,建议采用Equals进行判断,效率最高,但若是没法确保方法Equals的调用者是否不为null,建议仍是采用==或者 "XXXX".Equals(obj),若是须要用到多语言(国际化)判断的时候,能够考虑用Compare

6、拘留池(Interning

字符串操做(好比Compare)的作法是不少程序常见的操做,这样的操做可能形成内存中复制同一个字符串的多个实例(算法内部操做致使),为了达到节省内存的效果,CLR采用了一种叫“字符串留用的技术”(String Interning),开辟了一块名为“拘留池”的空间专门用于存放字符串,而拘留池在程序初始化的时候,会把元数据默认加载到“拘留池”中,并且不会受到垃圾回收器的影响,只有在程序被关闭的时候才会释放“拘留池”中的资源;

7、存储方式,大体分为如下3种:

1.     以常量的方式来定义很保存字符串,好比:var value = "abc";

2.     以对象的方式来保存到堆中:好比 var value = new string('a');

3.     以对象的方式构造而后存放到拘留池(其实常量的方式定义后,默认也会把字符串加入到驻留池中); 

能够参考如下代码和内存分配图进行理解:

    // 验证字符串常量默认加载到元数据,默认会把元数据中的字符串加载到拘留池
var  data =  " abc " ;        // 此声明方式,会把该变量定义为字符串常量,而后存入元数据中
    var a =  " a ";             // 同上
     var b =  " b ";             // 同上
     var c =  " c ";             // 同上
     var ab = a + b;          // 根据线程栈上的a、b地址获取到堆上的a、b实例,而后把两个实例的结果进行运算后产生一个新对象,最后新对象地址赋给ab变量
     var abc = a + b + c;     // 同上
     var abResult =  string.IsInterned(ab);         // 返回结果为null,也就是说没有把字符串"ab"存入拘留池中;
     var abcResult =  string.IsInterned(abc);      // 返回结果为"abc",也就是说已经把字符串(这里是常量)"abc"存放到拘留池中;
     var empty =  string.Empty;         // 初始化的时候,从String类型对象中获取静态属性Empty的数据;
     var strEmpty =  "";                // 产生一个值为空的String对象;

     var a1 =  " abc ";
     var a2 =  string.IsInterned(a1);
     var result =  object.ReferenceEquals(a1, a2);    

            

     注:默认是不从拘留池中加载,而是直接采用ldstr的特殊指令得到字符串”abc”,但能够确认的是”元数据”跟“拘留池”中的字符串是用个对象; 

8、案例分析

   1 . 如下代码的HashCode是否相同,它们是不是同个对象;

      var A = "ab" + "c";
      var B = "abc";
 
  2. 如下代码的HashCode是否相同,他们是不是同个对象:  
      var A = Console.ReadLine();   //输入"abc"
      var B = Console.ReadLine();   //输入"abc"
 
  3. 如下代码的HashCode是否相同,他们是不是同个对象:
      var A = Console.ReadLine(); //输入"abc"
      var B = Console.ReadLine(); //输入"abc"
      var A = string.Intern(B);

 结果请查看这里

相关文章
相关标签/搜索