为什么string在许多编程语言中是不可变的?
可能重复:
为什么string不能在Java和.NET中变化?
为什么.NETstring是不可变的?
有几种语言select了这种语言,比如C#,Java和Python。 如果为了节省内存或提高像比较这样的操作的效率,它对连接和其他修改操作有什么影响?
不可变的types通常是一件好事:
- 他们更好地工作并发(你不需要locking一些不能改变的东西!)
- 它们减less了错误:可变对象很容易被改变,当你不期望它会引入各种奇怪的错误(“远处行动”)
- 它们可以安全地共享(即对同一对象的多个引用),这可以减less内存消耗并提高caching利用率。
- 如果你必须采取一个可变对象的防御副本,共享也会使复制一个非常便宜的O(1)操作。 这是一件大事,因为复制是一个非常常见的操作(例如,当你想传递参数….)
因此,使string不可变是一个非常合理的语言deviseselect。
一些语言(特别是Haskell和Clojure等函数式语言)更进一步,使得几乎所有的东西都是不变的。 如果你对不变性的好处感兴趣,这个启发性的video非常值得一看。
对于不可变types有一些小缺点:
- 创build像串联这样更改的string的操作更为昂贵,因为您需要构build新的对象。 通常,如果使用像Rope这样的基于树的string数据结构,则连接两个不可变string的代价是O(n + m),尽pipe它可以低至O(log(m + n))。 另外,如果你真的需要高效地连接string,你总是可以使用像Java的StringBuilder这样的特殊工具。
- 大string的小改动可能导致需要构build大string的全新副本,这显然增加了内存消耗。 但是请注意,垃圾收集语言通常不是一个大问题,因为如果您不保留引用,旧副本将很快得到垃圾回收。
总的来说,不变性的优势远大于轻微的缺点。 即使你只对性能感兴趣,复制的并发优势和便宜性通常会使不可变的string比具有locking和防御性复制的可变string更具性能。
主要是为了防止编程错误。 例如,string经常用作散列表中的键。 如果他们可以改变,哈希表将被破坏。 这只是一个例子,在使用数据的过程中,数据发生变化会导致问题。 安全性是另一种方式:如果您在执行所请求的操作之前检查用户是否被允许在给定的path上访问文件,则包含该path的string最好不要变为可变的。
当你在做multithreading时,它变得更加重要。 不可变数据可以安全地在线程之间传递,而可变数据会导致无穷无尽的头痛。
基本上,不可变数据使得在其上工作的代码更容易推理。 这就是为什么纯粹的function语言试图保持一切不变的原因。
在Java中,不仅是String,而且所有的原始包装类(Integer,Double,Character等)都是不可变的。 我不清楚确切的原因,但我认为这些是所有编程scheme工作的基本数据types。 如果他们改变,事情可能会疯狂。 更具体地说,我将使用一个例子:假设你已经打开了一个到远程主机的套接字连接。 主机名是一个string,端口将是整数。 如果这些值在连接build立后被修改会怎么样?
就性能而言,Java从一个名为Literal Pool的单独内存部分向这些类分配内存,而不是从堆栈或堆中分配内存。 文字池被索引,如果你使用了一个string“String”两次,他们指向Literal池中的同一个对象。
将string设置为不可变也允许新的string引用变得容易,因为相同/相似的string将容易从先前创build的string的池中获得。 从而降低了创build新对象的成本。