由于字符串在.NET中是不可变的,为什么它们被复制用于简单的操作,如Substring
或Split
?例如,通过保持char[] value
,int start
并且int length
,一个串可以创建简单地指向一个现有的字符串,我们可以节省复制了许多简单的操作字符串的开销.所以我想知道,为什么选择复制字符串进行此类操作?
例如,这样做是为了支持当前的实施StringBuilder
吗?或者char[]
当只需要几个字符时,为了避免保留对大的引用?或者你能想到的任何其他原因?你能为这种设计提出利弊吗?
正如@cletus所提到并得到@Jon Skeet的支持,这更像是在问这个方面为什么.NET字符串与Java不同.
这基本上就是Java的工作方式.IMO有一些好处,IMO:
参考地点 - 数据和长度在同一个地方
更少的解引用 - 数据在字符串对象本身内的固定点; 无需取消引用另一个char数组
如Renaud所述,如果你有一个原始大字符串的单个字符子串,就会缺少别名.
最终会有更少的对象和变量.对于.NET字符串(假设没有浪费的缓冲区空间),总大小(在x86上)大约是20+2*n
字节.在Java中,你有大小的array(12 + 2*n
)字节和字符串本身(24字节:对象开销,引用,开始和计数;如果它曾经计算过,它还会缓存哈希值).所以对于一个空字符串,与Java的36相比,.NET版本大约需要20个字节.当然这是最糟糕的情况,它只会是"常数差异" - 但如果你使用了很多独立的字符串,那么最终意义重大.更多的垃圾收集器也可以看.
当然,当不发生上面的混叠时,其优点是需要更少的空间.
最后,它将取决于您的使用情况 - 编译器和运行时无法预测您的确切代码中更有可能使用哪种使用模式.
当前的字符串表示可能还有互操作的好处,但我对此肯定不够了解.
编辑:我不确定为什么你的问题收到了这么多有些恶意的答案.它当然不是表示字符串的"愚蠢"方式,它显然有效.在这种情况下,对数据丢失和复杂性的担忧几乎就是FUD,我相信 - Java字符串实现简单而强大.我个人怀疑 .NET的做事方式在大多数程序中都更有效,我怀疑MS做了研究来检查,但肯定会出现"共享"模式更好的情况.
如果您重复使用相同的字符串返回子字符串,当主字符串超出范围时会发生什么?
在最好的情况下,它需要保留在内存中,并且在所有子字符串也被释放之前无法收集,因此您最终会使用更多的内存.
这只是其中一个问题.
实际上,垃圾收集器几乎没有选择:
将整个原始字符串保留在内存中,即使只使用非常短的子字符串也可以使用.
释放原始字符串中未引用的部分,并仅保留子字符串.这会产生很多碎片,这意味着垃圾收集器可能不得不在某些时候重新定位字符串:无论如何我们最终会制作副本.
我确信它有它的用例,在处理子字符串时(比如处理大型XML文档时)它有时会更有效率.
但是,正如Jon所说,Java字符串对象需要更多空间,所以如果你有很多小字符串,它们实际上可以使用比.Net更多的内存.
这是一个权衡.
我认为,如果你的情况是真正重要的是如何管理内存并且你需要有一个完全可预测的行为,那么Java或.Net都不是最好的工具.
我们使用垃圾收集器,因为它们经过优化,可以在绝大多数情况下高效工作.
知道它们是如何工作的很重要,但是它们是否重新使用字符串更多地是对底层框架的优化,它不应该泄漏太多表面.
毕竟,GC是为了帮助我们.