为什么只有字符串是不可变的&不是其他数据类型

时间:2014-09-01 12:06:03

标签: c# vb.net

我总是想知道什么是可变性。为什么.net设计人员只开发了stringbuilder类来实现字符串类的可变性。考虑到int&而不是int的intbuilder无论数据类型如何,字符串都以完全相同的方式实现。

6 个答案:

答案 0 :(得分:3)

许多其他语言为字符串提供了类似的设计:带有StringBufferStringBuilder的Java,带有StringBuilder的Scala,带有MutableString though there are other, beter solutions in Python的Python。在C ++中,字符串是可变的,因此不需要构建器。

构建器存在字符串的原因是:

  1. 许多语言将字符串定义为不可变的(任何更改都需要内存中的新对象)
  2. 字符串趋势比较大,比int大得多
  3. [1]和[2]合并导致效率低下
  4. 构造函数不存在于int:

    的原因
    1. 它本身就是简单的数据结构
    2. 大多数CPU都有优化的指令来处理简单的数字(添加,带走等)
    3. 大多数CPU只需一个或几个周期就可以使用寄存器或快速CPU缓存来高效处理[2]指令
    4. [2]和[3]结合起来消除了对优化的需求
    5. 几乎没有必要改变int本身,但是,如果需要,可以使用BitConverterbinary shift operations

答案 1 :(得分:2)

为了帮助您了解为什么没有IntBuilderLongBuilderDecimalBuilder等),请考虑在设计这些类时,您将对这些类进行哪些操作。关于一个数字很少“建立”:与字符串不同,你可以追加,插入和删除,数字只能用新数字替换。

请注意,即使在新值基于旧值(例如,假设为Add的{​​{1}}或Multiply方法)的情况下,它基本上也是< em> replacement 操作,因为IntBuilder可以包含单个值。因此,您的IntBuilder最终会看起来像这样:

IntBuilder

这就是你需要一个可变的class IntBuilder { public int Value { get; set; } } 。也许一组很好的Int32ToStringEquals覆盖也很有用;也许,某些转化运算符让您在某些情况下将GetHashCode视为IntBuilder也会派上用场。但是,在上面的实现中捕获了该类的本质:所有其他“构建”操作都可以使用intValue的分配进行建模。但这不是一个有用的课程,原因有两个:

  • 您可以使用原始IntBuilder来改变单个方法范围内的整数,并且
  • 如果必须在其他方法中实现突变,则可以通过引用传递原始int

答案 2 :(得分:0)

这个问题必须重复,但我找不到。

您提出错误的问题,我们都希望大多数值类型都是不可变的,并且期望所有基本类型都是值类型。但是string是一种基本类型,它是一种引用类型。

请参阅&#34; In C#, why is String a reference type that behaves like a value type?&#34;,&#34; Is string a value type or a reference type?&#34;和&#34; Why is string a reference type?&#34;对于C#设计团队试图解决的问题。

(大多数编程语言都很难将字符串放入类型系统中。)

答案 3 :(得分:-1)

  

我认为你不考虑的是现代的记忆   电脑工作。

     

当你要求操作系统给你一些内存来存储数据时(如   string)该空间可以在内存地址空间中的任何位置......

     

所以,我们假设您要求操作系统存储10个字符的字符串(10 *   2个字节= 20个字节),所以你有20个字节,你放置你的   那里的字符串数据。

     

现在程序员认为,让我们在结尾处放置另一个角色   那个10个字符的字符串...所以你要求OS另外2个字节(a   单个字符)但发现那两个额外的字节位于   内存中的一些通用和随机位置....问题;你不能   一个地方有10个字符而另一个地方有1个字符......所以   每次增加字符串的字符串大小时解决这个问题   销毁后,从内存池中请求总长度。

     

Basic也这样做它只是透明的。你的字符串   被摧毁,你只是没有基本的记忆指针,所以不要   通知。

     

这是一个类似的帮助(我能想到最好的)。

     

您和一些朋友去TicketMaster网站尝试购买5   最新音乐会门票;你有座位编号523,524,   525,526和527.然后你的另一个朋友建议他们想要   来也是......所以你再次去了TicketMaster网站   希望你能买到座位528或522,这样你就可以坐在旁边   另一个......但该网站不会让你选择你想坐的地方。

     

这让你有两个选择。要么取消所有朋友的座位   并重新预订所有六个人或将最后一个人安排在其他地方......但是如果   你把它们放在其他地方,你可能很难找到它们   之后...所以你决定选择第一个选项并取消和   重新预订完整的号码。

来自Link我在OP的问题下发布了。



修改

http://www.programcreek.com/2013/04/why-string-is-immutable-in-java/解释为什么字符串是不可变的。这包括:

  • 字符串池中的要求:

字符串池(String intern pool)是方法区域中的特殊存储区域。创建字符串并且池中已存在该字符串时,将返回现有字符串的引用,而不是创建新对象并返回其引用。

  • 缓存哈希码:

字符串的哈希码经常在Java中使用。例如,在HashMap中。不可变保证哈希码总是相同的,因此它可以兑现而不用担心更改。这意味着,每次使用时都不需要计算哈希码。这样效率更高。

  • 促进使用其他物品:

为了具体化,请考虑以下程序:

HashSet<String> set = new HashSet<String>();
set.add(new String("a"));
set.add(new String("b"));
set.add(new String("c"));

for(String a: set)
a.value = "a";

在此示例中,如果String是可变的,则可以更改其值,这将违反set的设计(set包含非重复元素)。这个例子是为了简单起见而设计的,在真正的String类中没有值字段。

  • 安全

String被广泛用作许多java类的参数,例如网络连接,打开文件等。字符串不是不可变的,连接或文件将被更改并导致严重的安全威胁。该方法认为它连接到一台机器,但事实并非如此。可变字符串也可能导致Reflection中的安全问题,因为参数是字符串。

  • 不可变对象自然是线程安全的

因为无法更改不可变对象,所以可以在多个线程之间自由共享它们。这消除了进行同步的要求。

总之,为了提高效率和安全性,String被设计为不可变的。这也是为什么不可变类通常是首选的原因。

我还想澄清一下,这个答案可以参考多种编程语言。

答案 4 :(得分:-1)

每次生成一个字符串时,都会在堆中创建一个新实例,而int通常是在堆栈上完成操作

// increment int in loop
int c = 10;
for (int i = 0; i < 100; ++i)
{
    c += 5;
}
Console.WriteLine("c: {0}", c);

c是堆栈上的变量,增量将替换值而不使用额外的内存。

相反:

// concat string in loop
string acc = "";
for (int i = 0; i < 100; ++i)
{
    acc += "A";
}
Console.WriteLine("acc: {0}", acc);

这会在堆上创建1(string acc = "";)+ 100(acc += "A";)= 101个新对象,每个对象 使用更多内存("A""AA""AAA"等)对GC施加更多压力,因为收集了除最后一个之外的所有这些实例。当字符串很长时,这就成了性能问题。

使用:

// concat string with StringBuilder
var sb = new StringBuilder();
for (int i = 0; i < 100; ++i)
{
    sb.Append("A");
}
Console.WriteLine("sb: {0}", sb.ToString());

只创建了两个对象(StringBuilder和sb.ToString()),并在内部使用非托管内存进行追加,而无需创建新的中间字符串。只有sb.ToString(),内部未管理的字符串才会被复制到堆上的不可变字符串。

演示:https://dotnetfiddle.net/plteCr

答案 5 :(得分:-2)

performance reasons添加了{p> StringBuilder,特定于字符串。 intbuider没有任何意义,因为int是一个简单的类型:一个可变的int是没有意义的。正如another answer中所述: