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、被重写的两个方法GetHashCode与Equalscode
1. GetHashCode方法进行了重写,目的是为了知足两个字符串的判断;
2. Equals方法进行重写,其中Equals方法最终仍是调用了GetHashCode方法来进行判断;
5、“==”、Equals、Compare,字符串判断到底用哪一个好点?
1. String对“==”操做符进行重载,内部实现进行了空值判断后,再调用Equals进行判断(因此采用"=="操做符,不会抛出空指针异常)
2. String的Equals方法,由于调用Equals方法的时候,直接经过返回HashCode进行比较,效率最高,有可能对象为空,有可能会抛空指针异常,因此用的时候须要留意;
3. String的Compare方法:该方法是一个静态方法,内部实现是首先判断字符串的长度是否相等,若是长度不相等,直接返回结果,若是长度相等,则会采用逐个字符进行判断,若是方法中的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. 以对象的方式构造而后存放到拘留池(其实常量的方式定义后,默认也会把字符串加入到驻留池中);
能够参考如下代码和内存分配图进行理解:
注:默认是不从拘留池中加载,而是直接采用ldstr的特殊指令得到字符串”abc”,但能够确认的是”元数据”跟“拘留池”中的字符串是用个对象;
8、案例分析
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);
结果请查看这里