您的位置:首页 > 编程语言 > C#

《CLR via C#》读书笔记(10)– 我不知道的String

2013-01-18 11:00 204 查看
字符串这个东西我想所有人从接触程序开始应该就开始了解。但是在CLR中,仍然有一些东西我了解得并不清楚。

字符串的留用

我们经常在代码中定义一些常量字符串,有时候在多个地方定义的常量字符串是一样的。或者在我们的程序中定义了很多的string对象,这些对象里保存的字符串值都是一样的。

在CLR中String对象是不可变的,那么如果内存中有大量的值相同的String对象,是对内存的一种浪费。

其实可以只用一个String对象来保存字符串值,然后其他的引用都指向这个String对象。

在CLR中其实提供了这样的功能,它就是字符串留用。





如上图,CLR会以内存中保存一个留用字符串哈希表。在合希表中,Key为字符串的值,而Value则为字符串对象的引用。

.NET类库也提供了方法来访问这个哈希表。

public static string Intern(string str)


这个方法会从上图中的哈希表中查找该字符串是否被留用;若被留用测返回留用的字符串引用,否则创建一个该字符串的副本,然后将其引用加入到留用字符串哈希表中。


这样子起到了多个地方引用相同值的字符串时引用的是同一个对象,不用创建多个相同的对象。


一开始我觉得这不是多此一举吗,因为调这个方法不是也要传进来一个String对象吗?其实这里解决的是那种长时间驻留在内存中的相同字符串的内存浪费问题。因为传进来的string对象可能马上


会被GC释放掉,因为调用者可能会变为引用从该方法获得的string对象。像这样:


string original = "A";
original = String.Intern(original);


默认情况下,CLR会留用在代码中定义的所有的常量字符串。

写代码验证一下:

string str1 = "A";
string str2 = "A";
Console.WriteLine(object.ReferenceEquals(str1, str2));


输入结果:





有资料说这个默认行为在.NET 4.0中是可以改变的,下面我们去掉这个默认行为。通过给程序集添加如下标记:

[assembly: System.Runtime.CompilerServices.CompilationRelaxations( System.Runtime.CompilerServices.CompilationRelaxations.NoStringInterning)]


但是我在本机尝试了一下没有成功。

Base64字符串

之前用过Base64字符串,.NET框架库中也提供了相关的API(Convert类中提供)

public static string ToBase64String( byte[] inArray )

public static byte[] FromBase64String(string s)


但是以前只是知道他是将一个普通字符串转换成了一堆的看上去没有任何规律的字符。

其实所谓的Base64字符串是按照如下的规则生成的:

首先它将传入的字节数据的比特位中按顺序每次取6位,然后在前面补两个0,形成一个新的字节

对于形成的新的字节数据,因为每个字节值范围为0~63,因此他会按照一个有64个编码元素的编码表来编码新生成的字节。以下为编码表:





最后便生成了我们所看到的Base64字符串

由Base64的生成规则可以看出新成的字符串原初始字符串要长,大概是1.33倍,新生成的字符串从字面上看不出原始字符串的内容(从某种程度上是一种加密行为)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: