Java 为什么字符串在许多编程语言中是不可变的?

Java 为什么字符串在许多编程语言中是不可变的?,java,c++,string,immutability,Java,C++,String,Immutability,可能重复: 为此选择了几种语言,如C#、Java和Python。如果它是为了节省内存或提高比较等操作的效率,那么它对串联和其他修改操作有什么影响?不可变类型通常是一件好事: 它们在并发性方面工作得更好(您不需要锁定无法更改的内容!) 它们减少了错误:当你不希望可变对象被更改时,它很容易被更改,这会导致各种奇怪的错误(“远距离操作”) 它们可以安全地共享(即对同一对象的多个引用),这可以减少内存消耗并提高缓存利用率 共享还使得复制成为一个非常便宜的O(1)操作,而如果你必须获取一个可变对象的

可能重复:


为此选择了几种语言,如C#、Java和Python。如果它是为了节省内存或提高比较等操作的效率,那么它对串联和其他修改操作有什么影响?

不可变类型通常是一件好事:

  • 它们在并发性方面工作得更好(您不需要锁定无法更改的内容!)
  • 它们减少了错误:当你不希望可变对象被更改时,它很容易被更改,这会导致各种奇怪的错误(“远距离操作”)
  • 它们可以安全地共享(即对同一对象的多个引用),这可以减少内存消耗并提高缓存利用率
  • 共享还使得复制成为一个非常便宜的O(1)操作,而如果你必须获取一个可变对象的防御性副本,那么它将是O(n)。这是一个大问题,因为复制是一个非常常见的操作(例如,当您想要传递参数时……)
因此,使字符串不可变是一种非常合理的语言设计选择

有些语言(特别是Haskell和Clojure等函数式语言)甚至更进一步,几乎所有东西都是不可变的。如果您对不变性的好处感兴趣,那么这非常值得一看

不可变类型有几个小缺点:

  • 由于需要构造新对象,因此创建更改的字符串(如连接)的操作成本更高。通常,连接两个不可变字符串的成本是O(n+m),但如果使用基于树的字符串数据结构(例如,日志),成本可以低至O(log(m+n))。另外,如果您真的需要高效地连接字符串,您可以始终使用Java之类的特殊工具
  • 大字符串上的一个小更改可能会导致需要构造大字符串的一个全新副本,这显然会增加内存消耗。但是请注意,这在垃圾收集语言中通常不是一个大问题,因为如果不保留对旧副本的引用,旧副本将很快被垃圾收集

但总的来说,不变性的优点远远超过了它的缺点。即使您只对性能感兴趣,复制的并发性优势和廉价性通常也会使不可变字符串比具有锁定和防御复制的可变字符串性能更好。

它主要用于防止编程错误。例如,字符串经常用作哈希表中的键。如果它们可以更改,哈希表就会损坏。这只是一个例子,当你在使用一段数据时,它发生了变化,会导致问题。安全性是另一个问题:如果在执行用户请求的操作之前检查是否允许用户访问给定路径上的文件,则包含该路径的字符串最好是不可变的

在进行多线程处理时,它变得更加重要。不可变的数据可以在线程之间安全地传递,而可变的数据会带来无尽的麻烦


基本上,不可变的数据使在其上工作的代码更容易推理。这就是纯函数式语言试图保持所有内容不变的原因。

在Java中,不仅字符串,而且所有原始包装类(整数、双精度、字符等)都是不可变的。我不确定确切的原因,但我认为这些是所有编程方案工作的基本数据类型。如果他们改变,事情可能会变得疯狂。更具体地说,我将使用一个示例:假设您已打开到远程主机的套接字连接。主机名为字符串,端口为整数。如果在建立连接后修改了这些值,该怎么办


就性能而言,Java从称为文字池的单独内存部分(而不是从堆栈或堆)为这些类分配内存。文本池是索引的,如果您使用字符串“string”两次,它们将指向文本池中的同一对象。

将字符串设置为不可变也可以方便地引用新字符串,因为相同/相似的字符串将很容易从先前创建的字符串池中获得。从而降低了创建新对象的成本。

优点。但是,每个硬币都有两面。你刚刚列出了好的方面。缺点是什么?因为它是不可变的,我们不能仅仅通过挂起一个字符串来连接两个字符串;我们还必须创建一个新字符串,即使它与现有字符串仅相差一个字符,这意味着cpu会消耗内存分配。如果字符串是可变的,考虑到大量使用,它将在大型项目中创建许多难以检测的错误。这些错误的代价只会使字符串连接的CPU消耗问题变得微不足道。此外,在许多情况下,即使字符串是可变的,在进行轻微修改时仍然需要创建不同的字符串。但请注意,特别是在您的附加示例中,旧的不可变字符串通常会很快得到GC,因此对内存使用的影响只是暂时的。@Nawaz:这很有意义。在很可能的情况下,您的字符串是在年轻一代,那么它将得到清除非常快。至少在JVM上,您可以通过转义分析在堆栈上分配它,以便立即释放。即使它没有很快释放,你也不在乎,因为它保证在你再次需要内存之前被释放。GC是你的朋友,人们真的需要学会停止担心它。@Nawaz:这取决于你对fast的定义,但如果你将fast解释为“足够快,以至于你在实践中没有理由关心它”,那绝对是肯定的。如果你想学究式地说“尽可能快”,那么就不要了,但这显然是一个毫无意义的学术争论。延迟并不重要,如果