我总是想知道什么是可变性。为什么.net设计人员只开发了stringbuilder类来实现字符串类的可变性。考虑到int&而不是int的intbuilder无论数据类型如何,字符串都以完全相同的方式实现。
答案 0 :(得分:3)
许多其他语言为字符串提供了类似的设计:带有StringBuffer和StringBuilder的Java,带有StringBuilder的Scala,带有MutableString though there are other, beter solutions in Python的Python。在C ++中,字符串是可变的,因此不需要构建器。
构建器存在字符串的原因是:
构造函数不存在于int:
的原因答案 1 :(得分:2)
为了帮助您了解为什么没有IntBuilder
(LongBuilder
,DecimalBuilder
等),请考虑在设计这些类时,您将对这些类进行哪些操作。关于一个数字很少“建立”:与字符串不同,你可以追加,插入和删除,数字只能用新数字替换。
请注意,即使在新值基于旧值(例如,假设为Add
的{{1}}或Multiply
方法)的情况下,它基本上也是< em> replacement 操作,因为IntBuilder
可以包含单个值。因此,您的IntBuilder
最终会看起来像这样:
IntBuilder
这就是你需要一个可变的class IntBuilder {
public int Value { get; set; }
}
。也许一组很好的Int32
,ToString
和Equals
覆盖也很有用;也许,某些转化运算符让您在某些情况下将GetHashCode
视为IntBuilder
也会派上用场。但是,在上面的实现中捕获了该类的本质:所有其他“构建”操作都可以使用int
上Value
的分配进行建模。但这不是一个有用的课程,原因有两个:
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()
,内部未管理的字符串才会被复制到堆上的不可变字符串。
答案 5 :(得分:-2)
StringBuilder
,特定于字符串。 intbuider
没有任何意义,因为int是一个简单的类型:一个可变的int是没有意义的。正如another answer中所述: