“new String()”也是不可变的吗?

2022-08-31 13:33:19

我学习Java String已经有一段时间了。以下问题基于以下帖子

Java String 是 Java 中 String 的特殊
不可变性

  1. 不可变性:现在,通过不可变性,String类的设计使得公共池中的值可以在其他地方/变量中重用。如果 创建为String

    String a = "Hello World!";但是,如果我创建字符串,例如

    String b = new String("Hello World!");为什么这也是不可变的?(还是?由于这有一个专用的堆内存,我应该能够在不影响任何其他变量的情况下对其进行修改。那么,从设计上讲,有没有其他原因可以解释为什么作为一个整体被认为是不可变的呢?还是我上面的假设是错误的?String

  2. 我想问的第二件事是关于公共字符串池。如果我创建一个字符串对象作为

    String c = "";是否在池中创建了空条目?

这些已经有任何帖子了吗?如果是这样,有人可以分享链接吗?


答案 1

new String()是一个表达式,产生一个 ...和 a 是不可变的,无论它是如何产生的。StringString

(询问新的 String() 是否可变是荒谬的。它是程序代码,而不是值。但我认为这不是你的真正意思。


如果我创建一个字符串对象,就像在池中创建的空条目一样?String c = "";

是的;也就是说,为空字符串创建一个条目。空的.String

(为了迂腐起见,“”的池条目是在执行代码之前很久就创建的。实际上,它是在加载代码时创建的...甚至可能比这更早。


因此,我想知道新的堆对象是否也是不可变的,...

是的,它是。但不可变性是 String 对象的基本属性。所有对象。String

您看,API 根本没有提供任何更改 .因此(除了一些使用反射的危险和愚蠢的1技巧外),您无法改变.StringStringString

如果是这样,目的是什么?

Java被设计为一个不可变类的主要原因是简单性。它使编写正确的程序变得更加容易,并且如果核心字符串类提供了不可变的接口,则可以读取/推理其他人的代码。String

第二个重要原因是 的不可变性对 Java 安全模型具有根本性的影响。但我不认为这是原始语言设计中的驱动因素......在 Java 1.0 及更早版本中。String

根据答案,我发现对同一变量的其他引用是原因之一。请让我知道我是否正确理解了这一点。

不。它比这更根本。简单地说,所有对象都是不可变的。理解这一点不需要复杂的特殊情况推理。它只是>>是<<。String

为了记录,如果你想要一个在Java中可变的“类似字符串”的对象,你可以使用或。但这些是与字符串不同的类型。StringBuilderStringBuffer


1 - 这些技巧 (IMO) 危险和愚蠢的原因是,它们会影响可能由应用程序的其他部分通过字符串池共享的字符串的值。这可能会导致混乱...在某种程度上,下一个维护你的代码的人几乎没有机会追踪。


答案 2

字符串是不可变的,无论它是如何实例化的

1)简短的回答是肯定的,也是不可变的。new String()

因为您执行的每个可能的可变操作(如 等)都不会影响原始实例,并返回一个新实例replacetoLowerCaseStringString

您可以在 Javadoc 中检查 。公开的每个方法都会返回一个新实例,并且不会更改您在其上调用该方法的当前实例。StringpublicStringString

这在多线程环境中非常有用,因为您不必在每次传递或共享时都考虑可变性(有人会更改值)。 可以很容易地成为最常用的数据类型,因此设计人员祝福我们所有人不要每次都考虑可变性,并节省了我们很多痛苦。StringString

允许的不可变性 字符串池或缓存

正是由于不可变性属性,内部字符串池才成为可能,因为当在其他位置需要相同的 String 值时,将返回该不可变引用。如果是可变的,那么就不可能像这样共享以节省内存。StringString

字符串不可变性不是因为池化,而是不可变性有更多的好处。

字符串实习或池化是蝇量级设计模式的一个例子

2)是的,它将像任何其他实例一样被拘留,因为空白也与其他实例一样多。StringStringStringString

引用: