竹笋

首页 » 问答 » 环境 » 从String类型发散想到的一些东西计
TUhjnbcbe - 2023/11/15 21:27:00
白癜风用什么药膏好使 http://m.39.net/baidianfeng/a_4254069.html

值类型表示存储在栈上的类型,包括简单类型(int、long、double、short)、枚举、struct定义;

引用类型表示存在堆上的类型,包括数组、接口、委托、class定义;

string是引用类型

字符特殊性

不可变性。字符串创建后,重新赋值的话,不会更新原有值,而是将引用地址更新到一个新的内存地址上。留存性。.NET运行时有个字符串常量池的概念,在编译时,会将程序集中所有字符串定义集中到一个内存池中,新定义的字符串会优先去常量池中查看是否已存在,如果存在,则直接引用已存在的字符串,否则会去堆上重新申请内存创建一个字符串。下面是关于字符串的一些单元测试,仔细观察下各个不同:

Stringbuilder

字符串拼接是一个非常耗资源的操作,例如stringa=b+c,实际上创建了3个字符串b、c、bc。所以在这个时候就需要StringBuilder来专门执行字符串拼接操作了。

那么StringBuilder是如何实现的呢?

实际上StringBuilder内部维护了一个char数组,所有的appned类的操作都是将字符串转化为char存入数组。最后ToString()的时候才去组装string,减少了大量中间string的创建,是非常高效的字符串组装工具。

StringBuilder内部还有一个Capacity属性,用于定义数组的初始容量,默认值为25。超过容量会触发扩容操作。所以在实际操作中,如果我们能预估到拼接字符串的长度,在定义StringBuilder给Capacity属性附上一个合理的值,将会有更加高效的性能。

equals==

equals:比较字符串的值==:比较字符串的引用地址是否相同首先有个前提,我们所看到的equals,==,来自于System.Object对象,几乎所有的原生对象都对其进行了重写,才构成了我们目前的认知。重写equals必须重写GetHashCode。官方给出重写的实现约定如下:

Equals每个实现都必须遵循以下约定:

自反性(Reflexive):x.equals(x)必须返回true.对称性(Symmetric):x.equals(y)为true时,y.equals(x)也为true.传递性(Transitive):对于任何非null的应用值x,y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)必须返回true.一致性(Consistence):如果多次将对象与另一个对象比较,结果始终相同.只要未修改x和y的应用对象,x.equals(y)连续调用x.equals(y)返回相同的值l.非null(Non-null):如果x不是null,y为null,则x.equals(y)必须为falseGetHashCode:

两个相等对象根据equals方法比较时相等,那么这两个对象中任意一个对象的hashcode方法都必须产生同样的整数。在我们未对对象进行修改时,多次调用hashcode使用返回同一个整数.在同一个应用程序中多次执行,每次执行返回的整数可以不一致.如果两个对象根据equals方法比较不相等时,那么调用这两个对象中任意一个对象的hashcode方法,不一同的整数。但不同的对象,产生不同整数,有可能提高散列表的性能.请慎重重写Equals和GetHashCode!!重写Equals方法必须要重写GetHashCode!!

关于equals方法参数StringComparison

通常情况下最好使用Ordinal或者OrdinalIgnoreCase,性能上最为高效。

除非有特殊的需要,不要使用InvariantCulture或者InvariantCultureIgnoreCase,因为它要考虑所有Culture的字符转化对比情况,性能是极差的。

CurrentCulture和CurrentCultureIgnoreCase由于只有本地Culture对比,所以性能还可以接受。

参数传递

首先关于参数的存储,参数是存在栈上的。传递参数时,会将对象的“值”在栈copy一份,然后将副本的值传给方法。对象参数的传递分为两种“值传递”和“引用传递”。(注意这里的引号)

值传递。默认的参数传递都是这种方式。会将对象的值在栈copy一份,然后将复制集的值传给方法。这里的值对于值类型来说,即为对象副本的值。对于引用类型来说,即为对象在堆上的地址。引用传递。可以通过ref out关键字实现。对于值类型,会直接传入原对象在栈上的引用。对于引用类型,会传入原有对象的堆地址的引用。这里string虽然是引用类型,但是产生的效果缺和值类型参数传递一样的。大家参考上面关于string的特性思考下原因。

静心慢慢回味下列单元测试

refout

refout都是用来标识通过引用传递方式传参。不同的是,ref需要参数在方法调用前初始化,out则要求参数在方法体内赋值。

装箱拆箱

装箱,即值类型转化为引用类型;从内存存储角度,将值类型从栈的值copy,然后放到堆上,并附加额外的引用类型功能内存占用(如类型指针、同步块索引等)。

拆箱,即引用类型转化为值类型。从内存存储角度,获取引用类型的指针,得到值copy,放到栈上。

从性能角度上,装箱的性能损耗拆箱的性能损耗。在实际运用中,我们要尽量避免装箱和拆箱,这也是泛型类型出现后,一个非常大的作用就是避免了装箱拆箱的大量操作。

1
查看完整版本: 从String类型发散想到的一些东西计