[转] 深入探究 String 与 StringBuilder 内部原理

转自:深入探究 String 与 StringBuilder 内部原理

System.String 类型一直是我们不断讨论的话题,它是一个用于对字符串进行存储和操作的这么一个类型。

System.String 也是 C# 基础类型中唯一的引用类型。但是,它却具有很多值类型的特点。

我们来看一段简单的代码:

1  string text = "White";
2  string temp = text;
3  temp = "Black";
4  Console.WriteLine(text);
5  Console.ReadKey();

按照引用的理论,此处 temp 变量应该是存储的 text 变量的地址,那么修改 temp 变量的值,text 的值就应该随之改变。

那么,此时 text 变量的值应该就是 "Black",但事实上经过测试 text 变量的值还是 "White"。

那就说明 temp 变量肯定不是存储的 text 变量的地址。但,这样又违背了它是引用类型的这一特点,那它的内部究竟是怎么样处理的呢?

据我了解,微软应该是在 String 类型中引入了 Copy-On-Write(写时拷贝) 技术,先来简要说明一下什么是 Copy-On-Write 技术:

简单来说,在复制一个对象时并不是真的在内存中把原来对象的数据复制一份到另外一个地址,而是在新对象的内存映射表中指向同原对象相同的位置,

并且把那块内存的 Copy-On-Write 位设为 1。在对这个对象执行读操作的时候,内存数据没有变动,直接执行就可以。

在写的时候,才真正将原始对象复制一份到新的地址,修改新对象的内存映射表到这个新的位置,然后往这里写。

有一定经验的程序员应该都知道,Copy-On-Write(写时拷贝) 技术使用了 "引用计数" 方式,会有一个变量用于保存引用的数量。

当第一个类构造时,String 的构造函数会根据传入的参数从堆上分配内存,当有其它类需要这块内存时,这个计数为自动累加。

当有类析构时,这个计数会减一,直到最后一个类析构时,此时的引用计数为 1 或是 0,此时,程序才会真正的释放这块从堆上分配的内存。

说白了,"引用计数" 就是 String 类中写时拷贝的原理!

事实上,String 还是一个不可变的数据类型,一旦对 String 类型的对象进行了初始化,该字符串对象就不能改变了。

为了说明这一点,我们再来看一小段很简单的代码:

1  string name = "Adamas";
2  name += " is a gentleman.";

在执行这段代码时,首先创建一个名为 name 的 String 类型的对象,并初始化为 "Adamas"。

此时,.NET 运行库会为该字符串分配足够的内存来保存这个文本,然后,再设置变量 name,来表示这个字符串实例。

从语法上看,第二行代码是将更多的文本添加到此字符串中。在我初学 C# 语言的时候,我也是这么理解的。

实际上却并非如此,而是创建一个新的字符串实例,给他分配足够的内存,然后存储合并的所有文本。

把第一行代码中的文本:"Adamas" 复制到新字符串中,再加上第二行代码中的文本:" is a gentleman."。

然后更新存储在 name 变量中的内存地址,使变量正确的指向新的字符串对象。旧的字符串对象被销毁了引用,并等待系统回收。

这样的方式本身并没有问题,但是如果需要频繁的进行字符串的操作的话,那就存在极大地性能问题。

因此,为了解决这一问题,微软推出了 System.Text.StringBuilder 类。在 StringBuilder 类中,仅限于替换、添加和删除字符串中文本的操作,但它的效率远远高于 String。

StringBuilder stringBuilder = new StringBuilder(30,300);

StringBuilder 类在初始化的时候,提供许多构造函数用来初始化当前实例的初始大小和可存储的最大字符数以及用来初始化当前实例的字符串。

实际上,当我们创建 StringBuilder 对象的时候,.NET 运行库会为当前的对象在内存中分配一块缓存区域,用以对字符串操作的预留空间。

在使用 StringBuilder 类的时候,最好将容量设置为字符串可能的最大长度,确保 StringBuilder 不需要重复分配内存。

如果字符的容量超过设置的最大容量,.NET 运行库将自动分配内存并翻倍。

对于我们 .NET 程序员而言,StringBuilder 与 String 的不同之处就在于,StringBuilder 可以显示的设置分配内存的大小,

而 String 只能根据你初始化时的字符串的大小由系统分配足够的内存。

所以,当要对字符串进行频繁的操作的时候,在 String 和 StringBuilder 之间,我们应该选择 StringBuilder。

时间: 2024-10-18 07:23:17

[转] 深入探究 String 与 StringBuilder 内部原理的相关文章

String和StringBuilder效率不同的原理

在做实验的时候,中间有一个任务为一个图的toString.,用来打印每条边每个点的信息. 其中用到了字符串的链接 我当时用的是String 的 "+"操作, 但是图怎么也无法输出,因为有三十多万条边,在大量的字符串的拼接的时候,"+"特别耗时间和内存. 然后我通过网上查找,选择用StringBuilder的方法解决了这个问题. StringBuilder str = new StringBuilder(); str.append("lalalallal&q

java中String与StringBuilder的区别

本篇文章介绍了,java中String与StringBuilder的区别. 相信大家对 String 和 StringBuffer 的区别也已经很了解了,但是估计还是会有很多同志对这两个类的工作原理有些不清楚的地方,今天我在这里重新把这个概念给大家复习一下,顺便牵出 J2SE 5.0 里面带来的一个新的字符操作的类—— StringBuilder (先别忙着扔我砖头,我还算清醒,我这里说的不是 C #, Java 也有 StringBuilder 类).那么这个 StringBuilder 和

string和stringbuilder的个人总结

String和StringBuilder的深入解析   前言:本文出发点是我们开发的过程中是否真正的理解stringbuilder的使用,string字符串操作的是如何实现(哈希表),stringbuilder是否设置默认值容量,什么时候才用stringbuilder. 一概念String和stringbulider的理解 string是我们用的最多的类型之一,是一个特殊的引用类型,直接派生于Object,因此它的值储存在托管堆上.构造一个新字符串的时候,不需要用new.它是”不可变的“.初始化

关于 String,StringBuilder,StringBuffer

关于 String,StringBuilder,StringBuffer 的讨论,已有很多文章:在这里,我希望能刨根问底,更进一步的理解其中的原理. String String 是final类型,不可继承的类:内部存储是字符数组(char[]),也是final ,不可更改: /** 源码中 String 类的声明 */ public final class String implements java.io.Serializable, Comparable<String>, CharSeque

StringBuilder &amp;&amp; StringBuffer原理浅析

本文主要以简单的String/StringBuilder/StringBuffer操作来看这三个类的实现原理.什么简单操作呢?那就是StringBuilder与StringBuffer的append() && toString()两个方法.示例代码如下: public class TestStringBuffer_Builder { public static void main(String[] args) { TestStringBuffer_Builder testStringBuf

Java字符串的String、StringBuilder、StringBuffer三者特性详解

一.不可变String类型 字符串是计算机程序设计中的,最常见行为,Java的字符串操作最主要的类是String,并且String对象是不可变的(Immutable),即对象一旦创建在内存中,那么它的内容就不再改变.虽然String类中提供很多方法看起来像是可以修改String对象,比如trim().subString()等等,但是实际上它们并没有改变原来的字符串对象,这些方法传递的只是引用的一个拷贝,所以重新创建了一个String类型的对象,并且有了新的引用. 例如下面一段代码可以说明Stri

转:String StringBuffer StringBuilder区别

转自:http://www.iteye.com/topic/522167 作者:每次上网冲杯Java时,都能看到关于String无休无止的争论.还是觉得有必要让这个讨厌又很可爱的String美眉,赤裸裸的站在我们这些Java色狼面前了.嘿嘿.... 众所周知,String是由字符组成的串,在程序中使用频率很高.Java中的String是一个类,而并非基本数据类型. 不过她却不是普通的类哦!!! [镜头1] String对象的创建       1.关于类对象的创建,很普通的一种方式就是利用构造器,

java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题

java泛型(二).泛型的内部原理:类型擦除以及类型擦除带来的问题 参考:java核心技术 一.Java泛型的实现方法:类型擦除 前面已经说了,Java的泛型是伪泛型.为什么说Java的泛型是伪泛型呢?因为,在编译期间,所有的泛型信息都会被擦除掉.正确理解泛型概念的首要前提是理解类型擦出(type erasure). Java中的泛型基本上都是在编译器这个层次来实现的.在生成的Java字节码中是不包含泛型中的类型信息的.使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉.这个过程就称为类型

string和StringBuilder的区别,用法和详解

1.string 1.概念:string是引用类型,我们比较的是对象的值,而不是对象的本身. string strA="abcde"; string strB="abc"; string strC="de"; Console.WriteLine(strA == (strB+strC));//true Console.WriteLine((object)strA == (object)(strB+strC));//false 2.string对象是