先看看MS给出的官方解释吧

http://msdn.microsoft.com/zh-cn/library/system.text.stringbuilder(VS.80).aspx

String 对象串联操作总是用现有字符串和新数据创建新的对象。StringBuilder 对象维护一个缓冲区,以便容纳新数据的串联。如果有足够的空间,新数据将被追加到缓冲区的末尾;否则,将分配一个新的、更大的缓冲区,原始缓冲区中的数据被复制到新的缓冲区,然后将新数据追加到新的缓冲区。

String 或 StringBuilder 对象的串联操作的性能取决于内存分配的发生频率。

给实现者的说明 此实现的默认容量是 16,默认的最大容量是 Int32.MaxValue。

我只截取了最核心的一段,从这段我们就基本可以明白,StringBuilder的(后面直接简称sb,无节操的兄弟们,不要乱想,我也尽量不引导你们)实现,不过不看看源码,只看文档还是比较但蛋疼,理解不深。所以还是来看看其实现吧。

二话不说,先上一段定义,ok(只取了几个构造函数)

public sealed class StringBuilder : ISerializable
{
    // Methods
    public StringBuilder();
    public StringBuilder(int capacity);
    public StringBuilder(int capacity, int maxCapacity);
}
那我们最常用的两个,一个是无参构造,一个是整形构造,查看其源码其实都是调用了下面这个构造函数,给出其源码
public StringBuilder(int capacity, int maxCapacity)
{
    this.m_currentThread = Thread.InternalGetCurrentThread();
    if (capacity > maxCapacity)
    {
        throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_Capacity"));
    }
    if (maxCapacity < 1)
    {
        throw new ArgumentOutOfRangeException("maxCapacity", Environment.GetResourceString("ArgumentOutOfRange_SmallMaxCapacity"));
    }
    if (capacity < 0)
    {
        throw new ArgumentOutOfRangeException("capacity", string.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_MustBePositive"), new object[] { "capacity" }));
    }
    if (capacity == 0)
    {
        capacity = Math.Min(0x10, maxCapacity);
    }
    this.m_StringValue = string.GetStringForStringBuilder(string.Empty, capacity);
    this.m_MaxCapacity = maxCapacity;
}
两个参数一个是容量大小,另一个是最大容量。
这个构造做了些什么
1.  获取当前线程句柄
2.  做一些必要性的验证和判断
3.  调用了这个方法
string.GetStringForStringBuilder(string.Empty, capacity);
 
这个方法最终调用了这个方法
internal static unsafe string GetStringForStringBuilder(string value, int startIndex, int length, int capacity)
{
    string str = FastAllocateString(capacity);
    if (value.Length == 0)
    {
        str.SetLength(0);
        return str;
    }
    fixed (char* chRef = &str.m_firstChar)
    {
        fixed (char* chRef2 = &value.m_firstChar)
        {
            wstrcpy(chRef, chRef2 + startIndex, length);
        }
    }
    str.SetLength(length);
    return str;
}
其实就是分配了string控件,复制了一份,并返回了。

然后我们看下append方法,很多重载,其实都是调用了

public StringBuilder Append(string value)
{
    if (value != null)
    {
        string stringValue = this.m_StringValue;
        IntPtr currentThread = Thread.InternalGetCurrentThread();
        if (this.m_currentThread != currentThread)
        {
            stringValue = string.GetStringForStringBuilder(stringValue, stringValue.Capacity);
        }
        int length = stringValue.Length;
        int requiredLength = length + value.Length;
        if (this.NeedsAllocation(stringValue, requiredLength))
        {
            string newString = this.GetNewString(stringValue, requiredLength);
            newString.AppendInPlace(value, length);
            this.ReplaceString(currentThread, newString);
        }
        else
        {
            stringValue.AppendInPlace(value, length);
            this.ReplaceString(currentThread, stringValue);
        }
    }
    return this;
}

这里做了什么呢,

  1. 获取新字符串的长度,
  2. NeedsAllocation方法判断当前容量是否可以容纳新串,如果不能,重新生成新字符串

否则直接添加到旧的字符串中,实现方法如下

internal unsafe void AppendInPlace(string value, int currentLength)
{
    int length = value.Length;
    int index = currentLength + length;
    fixed (char* chRef = &this.m_firstChar)
    {
        fixed (char* chRef2 = &value.m_firstChar)
        {
            wstrcpy(chRef + currentLength, chRef2, length);
        }
        chRef[index] = '\0';
    }
    this.m_stringLength = index;

}

了解了上面的大概内容基本上也就知道了,sb的实现原理,正如msdn解释的一样。

那么知道了这些有个屁用呢,msdn中也解释了,性能取决于内存分配的发生频率,既然知道了性能问题,那么以后我们写的时候是不是需要估计下字符串的大小呢。比如我们经常在后台拼接html字符串,sb的初始默认大小是16,每次容量不够,大小翻倍重新分配,(

int capacity = currentString.Capacity * 2;创建新字符串的函数代码忘了贴,看了前面的实现基本就能猜到了,其中就这一句对我们比较有用

)相信我们随便拼一个长度就要远大于16吧,这就导致了大量的内存分配发生,降低了效率,(这里就可以猜测string的连接操作应该是每次都进行内存分配)所以,sb初始预估大小还是很有用的。

StringBuilder的实现的更多相关文章

  1. 测试一下StringBuffer和StringBuilder及字面常量拼接三种字符串的效率

    之前一篇里写过字符串常用类的三种方式<java中的字符串相关知识整理>,只不过这个只是分析并不知道他们之间会有多大的区别,或者所谓的StringBuffer能提升多少拼接效率呢?为此写个简 ...

  2. 计算机程序的思维逻辑 (30) - 剖析StringBuilder

    上节介绍了String,提到如果字符串修改操作比较频繁,应该采用StringBuilder和StringBuffer类,这两个类的方法基本是完全一样的,它们的实现代码也几乎一样,唯一的不同就在于,St ...

  3. StringBuilder的使用

    今天用到了StringBuilder来拼接查询语句,发现这个真好用,决定做个小结. 百度一个StringBuilder的定义:String 对象是不可改变的.每次使用 System.String 类中 ...

  4. Java--String 和StringBuilder、StringBuffer 的区别?

    1.String是只读字符串,引用的字符串内容是无法改变的. 2.StringBuffer和StringBuilder的字符串对象可以直接进行修改. 3.StringBuilder没有被synchro ...

  5. java中 String StringBuffer StringBuilder的区别

    * String类是不可变类,只要对String进行修改,都会导致新的对象生成. * StringBuffer和StringBuilder都是可变类,任何对字符串的改变都不会产生新的对象. 在实际使用 ...

  6. String、StringBuffer与StringBuilder之间区别

    关于这三个类在字符串处理中的位置不言而喻,那么他们到底有什么优缺点,到底什么时候该用谁呢?下面我们从以下几点说明一下 1.三者在执行速度方面的比较:StringBuilder >  String ...

  7. String StringBuffer StringBuilder

    package com.test; import java.util.Date; /*** * * // 输出的结果是:// 来一个测试// 来一个测试如果只输出这句就证明了String是不可变的// ...

  8. StringBuffer与StringBuilder的简单理解

    联系:两者都适用于字符串的操作,都可以随便对字符串的内容进行变更操作,都继承至AbstractStringBuilder. 区别:StringBuffer是线程安全的,方法都加了synchronize ...

  9. 关于StringBuffer和StringBuilder

    StringBuffer 字符串特点:字符串是常量:它们的值在创建之后不能更改. 字符串的内容一旦发生了变化,那么马上会创建一个新 的对象. 注意: 字符串的内容不适宜频繁修改,因为一旦修改马上就会创 ...

  10. string,stringbuilder,stringbuffer用法

    总结:1.如果要操作少量的数据用 = String   ==================================>字符串常量2.单线程操作字符串缓冲区 下操作大量数据 = Strin ...

随机推荐

  1. Selenium 切换句柄

    最近用了网络上别人的一段切换窗口的code每次成功了,不错,学习 // 根据Title切换新窗口 public boolean switchToWindow_Title(WebDriver drive ...

  2. Ionic2 开发笔记(1)ionic2 +angular2搭建

    1.去node.js官网下载对应版本https://nodejs.org/en/(不会请看OnsenUi搭载,里面有详细过程) 2.然后通过npm下载Ionic和cordova $ npm insta ...

  3. 【2017-03-16】TSQL基本编程、存储过程、触发器

    一.TSQL基本编程 1.定义变量 :declare @变量名 数据类型        变量名前面必须加"@"符号 declare @aaa int; declare @bbb n ...

  4. Android OkHttp使用与分析

    安卓开发领域,很多重要的问题都有了很好的开源解决方案,例如网络请求 OkHttp + Retrofit 简直就是不二之选."我们不重复造轮子不表示我们不需要知道轮子该怎么造及如何更好的造!& ...

  5. 关于web测试收集

    页面部分 页面清单是否完整(是否已经将所需要的页面全部都列出来了) 页面是否显示(在不同分辨率下页面是否存在,在不同浏览器版本中页面是是否显示) 页面在窗口中的显示是否正确.美观(在调整浏览器窗口大小 ...

  6. Unity获取安卓手机运营商,电量,wifi信号强度,本地Toast,获取已安装apk,调用第三方应用,强制自动重启本应用

    一个完整的游戏项目上线需要不断的完善优化,但是到了后期的开发不再仅仅是游戏了,它的复杂度远远大于纯粹的应用开发.首先必须要考虑的就是集成第三方SDK,支付这块渠道商已经帮你我们做好了,只需要按照文档对 ...

  7. 带金属光泽的模型shader的实现

    最近捣鼓了一下金属光泽的shader的实现,在一些高模展示的时候或者模型的金属部分的表现的时候,我们需要给模型添加一些金属光泽,表现出一个模型某些金属装备上有一定的反光.今天我主要写一种基于贴图实现的 ...

  8. 模拟在内存中的数据库DataSet相关的类

    这篇连着上一篇DataReader相关类. 下面两段话是在msdn官网摘下来:       .NET Framework 数据提供程序是专门为数据操作以及快速.只进.只读访问数据而设计的组件.Conn ...

  9. 初识 Javascript.02 -- Date日期、Math对象、数据类型转换、字符串、布尔Boolean、逻辑运算符、if else 、三元表达式、代码调试方法、

    Date()对象: Date对象用于处理日期和时间. 1.1 Math对象  ◆Math.ceil()   天花板函数    向上取整  只取整数,不足则进1 ◆Math.floor()  地板函数 ...

  10. Java Unicode编码 及 Mysql utf8 utf8mb3 utf8mb4 的区别与utf8mb4的过滤

    UTF-8简介 UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,也是一种前缀码.它可以用来表示Unicode标准中的任何 ...