StringBuilder的实现
先看看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; } |
这里做了什么呢,
- 获取新字符串的长度,
- 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的实现的更多相关文章
- 测试一下StringBuffer和StringBuilder及字面常量拼接三种字符串的效率
之前一篇里写过字符串常用类的三种方式<java中的字符串相关知识整理>,只不过这个只是分析并不知道他们之间会有多大的区别,或者所谓的StringBuffer能提升多少拼接效率呢?为此写个简 ...
- 计算机程序的思维逻辑 (30) - 剖析StringBuilder
上节介绍了String,提到如果字符串修改操作比较频繁,应该采用StringBuilder和StringBuffer类,这两个类的方法基本是完全一样的,它们的实现代码也几乎一样,唯一的不同就在于,St ...
- StringBuilder的使用
今天用到了StringBuilder来拼接查询语句,发现这个真好用,决定做个小结. 百度一个StringBuilder的定义:String 对象是不可改变的.每次使用 System.String 类中 ...
- Java--String 和StringBuilder、StringBuffer 的区别?
1.String是只读字符串,引用的字符串内容是无法改变的. 2.StringBuffer和StringBuilder的字符串对象可以直接进行修改. 3.StringBuilder没有被synchro ...
- java中 String StringBuffer StringBuilder的区别
* String类是不可变类,只要对String进行修改,都会导致新的对象生成. * StringBuffer和StringBuilder都是可变类,任何对字符串的改变都不会产生新的对象. 在实际使用 ...
- String、StringBuffer与StringBuilder之间区别
关于这三个类在字符串处理中的位置不言而喻,那么他们到底有什么优缺点,到底什么时候该用谁呢?下面我们从以下几点说明一下 1.三者在执行速度方面的比较:StringBuilder > String ...
- String StringBuffer StringBuilder
package com.test; import java.util.Date; /*** * * // 输出的结果是:// 来一个测试// 来一个测试如果只输出这句就证明了String是不可变的// ...
- StringBuffer与StringBuilder的简单理解
联系:两者都适用于字符串的操作,都可以随便对字符串的内容进行变更操作,都继承至AbstractStringBuilder. 区别:StringBuffer是线程安全的,方法都加了synchronize ...
- 关于StringBuffer和StringBuilder
StringBuffer 字符串特点:字符串是常量:它们的值在创建之后不能更改. 字符串的内容一旦发生了变化,那么马上会创建一个新 的对象. 注意: 字符串的内容不适宜频繁修改,因为一旦修改马上就会创 ...
- string,stringbuilder,stringbuffer用法
总结:1.如果要操作少量的数据用 = String ==================================>字符串常量2.单线程操作字符串缓冲区 下操作大量数据 = Strin ...
随机推荐
- 技术分享,学术报告presentation 常用的承接句
前言 现在即使是搞技术,做科研的,也需要在不同的场合,用ppt来做分享,做汇报,做总结. 如果国际会议,研讨会,或者在外企,国外工作,英文的presentation就更加必不可少.英语的提升需要大家从 ...
- 详解Swing中JTree组件的功能
JTree组件是另外一个复杂组件,它不像 JTable 那样难用,但是也不像 JList 那么容易.使用 JTree 时麻烦的部分是它要求的数据模型. JTree组件的功能来自树的概念,树有分支和叶子 ...
- 在.NET项目中使用PostSharp,使用MemoryCache实现缓存的处理
在之前一篇随笔<在.NET项目中使用PostSharp,实现AOP面向切面编程处理>介绍了PostSharp框架的使用,试用PostSharp能给我带来很多便利和优势,减少代码冗余,提高可 ...
- 【Javascript】搞定JS面试——跨域问题
什么是跨域? 为什么不能跨域? 跨域的解决方案都有哪些(解决方法/适用场景/get还是post)? 一.什么是跨域? 只要协议.域名.端口有任何一个不同,就是跨域. ...
- C++—引用的作用
引入 C语言中函数有两种传参的方式: 传值和传址.以传值方式, 在函数调用过程中会生成一份临时变量用形参代替, 最终把实参的值传递给新分配的临时变量即形参. 它的优点是避免了函数调用的副作用, 确无法 ...
- linux 私房菜 CH7 Linux 档案与目录管理
路径 ``` . 此层目录 .. 上一级目录 前一个工作目录 ~ 当前用户的家的目录 ``` 变换目录 cd 显示目录 pwd [-P] -P 显示出确实的路径,而非使用链接 (link) 路径. 创 ...
- Sql Server优化---统计信息维护策略
本位出处:http://www.cnblogs.com/wy123/p/5748933.html 首先解释一个概念,统计信息是什么: 简单说就是对某些字段数据分布的一种描述,让SQL Server大概 ...
- python学习之路-书籍推荐
学python有一段时间了,总结走来的路,发现还是看书靠谱,当然也要多实践. 一.入门篇 1.简明 Python 教程(A Byte of python) http://www.kuqin.com/a ...
- java日期转换
在java开发过程中,时间的转换时必须掌握的=========下面把时间转换做个总结,有可能不是很全面 时间格式只有两种 yyyy-MM-DD yyyy/MM/DD 时间的类型:字符串类型.sql类型 ...
- 关于Union和Union All的区别以及用法
有些时候我们在查询的时候会碰到这么一个问题,就是一条SQL不能查出来你想要的结果;首先,我们必须明确一条查询SQL执行之后数据库会给我们返回什么,他会返回符合条件的一个结果集,而当你一条查询SQL不能 ...