在一次采访中,有人问我为什么String是不可变的

我是这样回答的:

当我们在java中创建一个字符串,如string s1="hello";然后一个 对象将在字符串池(hello)中创建,s1将 指着你好。现在如果我们再次执行String s2="hello";然后 不会创建另一个对象,但s2将指向hello 因为JVM将首先检查相同的对象是否在 是否为字符串池。如果不存在,则只创建一个新的,否则不存在。

现在如果假设java允许字符串可变,那么如果我们将s1改为hello world,那么s2值也将是hello world,所以java字符串是不可变的。

谁能告诉我我的答案是对的还是错的?


当前回答

String类是FINAL,这意味着你不能创建任何类来继承它,改变基本结构,使Sting可变。

另一件事,实例变量和String类的方法是这样的,你不能改变String对象一旦创建。

您所添加的内容并没有使字符串成为不可变的。这些都说明了字符串是如何存储在堆中的。字符串池在性能上也有巨大的差异

其他回答

恕我直言,这是最重要的原因:

字符串在Java中是不可变的,因为字符串对象缓存在 字符串池。由于缓存的字符串字面值在多个字符串之间共享 客户那里总有风险,一个客户的行动就会影响到 都是另一个客户。

参考:为什么字符串是不可变或最终在Java

如果HELLO是你的字符串,那么你不能把HELLO改成HILLO。这个性质叫做不可变性。

你可以有多个指针字符串变量指向HELLO字符串。

但是如果HELLO是char Array,那么你可以将HELLO改为HILLO。例如,

char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this

答:

编程语言具有不可变的数据变量,因此可以作为键、值对中的键使用。字符串变量用作键/索引,因此它们是不可变的。

String类是FINAL,这意味着你不能创建任何类来继承它,改变基本结构,使Sting可变。

另一件事,实例变量和String类的方法是这样的,你不能改变String对象一旦创建。

您所添加的内容并没有使字符串成为不可变的。这些都说明了字符串是如何存储在堆中的。字符串池在性能上也有巨大的差异

你说得对。java中的字符串使用字符串池字面量的概念。创建字符串时,如果该字符串已经存在于池中,则将返回现有字符串的引用,而不是创建一个新对象并返回其引用。如果字符串不是不可变的,用一个引用更改字符串将导致其他引用得到错误的值。

我还要补充一点,因为String是不可变的,所以对于多线程来说是安全的,单个String实例可以在不同的线程之间共享。这避免了线程安全同步的使用,字符串是隐式线程安全的。

这可能与安全性没有多大关系,因为安全实践建议使用字符数组作为密码,而不是字符串。这是因为当不再需要数组时,可以立即删除数组。不同的是,字符串不能被擦除,因为它是不可变的。在垃圾收集之前可能需要很长时间,在内容被覆盖之前可能需要更长的时间。

我认为选择不变性是为了允许共享字符串,它们很容易分裂。字符串赋值,选择子字符串变成了一个常数时间的操作,字符串比较也是,因为可重用的哈希码是字符串数据结构的一部分,可以首先进行比较。

从另一方面来说,如果原始字符串很大(比如大型XML文档),那么从中选取少量符号可能会防止整个文档被垃圾收集。因此,后来的Java版本似乎远离了这种不变性。现代c++既有可变(std::string)版本,从c++ 17开始也有不可变(std::string_view)版本。