Java 中字符串的不可变性

2022-08-31 05:48:18

请考虑以下示例。

String str = new String();

str  = "Hello";
System.out.println(str);  //Prints Hello

str = "Help!";
System.out.println(str);  //Prints Help!

现在,在Java中,String对象是不可变的。那么为什么可以为对象分配值“帮助!这难道不是与Java中字符串的不变性相矛盾吗?任何人都可以解释一下不变性的确切概念吗?str

编辑:

还行。我现在明白了,但只是一个后续问题。下面的代码呢:

String str = "Mississippi"; 
System.out.println(str); // prints Mississippi 

str = str.replace("i", "!"); 
System.out.println(str); // prints M!ss!ss!pp! 

这是否意味着再次创建两个对象(“Mississippi”和“M!ss!ss!pp!”),并且引用指向方法后的不同对象?strreplace()


答案 1

str不是对象,而是对对象的引用。 并且是两个不同的对象。因此,指向一个字符串。您可以更改它指向的内容,但不能更改它指向的内容。"Hello""Help!"Stringstr

以以下代码为例:

String s1 = "Hello";
String s2 = s1;
// s1 and s2 now point at the same string - "Hello"

现在,我们能做的1 不会影响 的值。它们引用同一个对象 - 字符串 - 但该对象是不可变的,因此无法更改。s1s2"Hello"

如果我们做这样的事情:

s1 = "Help!";
System.out.println(s2); // still prints "Hello"

在这里,我们看到了改变对象和改变引用之间的区别。 仍然指向我们最初设置为指向的同一对象。设置为仅更改引用,而它最初引用的对象保持不变。s2s1s1"Help!"String

如果字符串可变的,我们可以做这样的事情:

String s1 = "Hello";
String s2 = s1;
s1.setCharAt(1, 'a'); // Fictional method that sets character at a given pos in string
System.out.println(s2); // Prints "Hallo"

编辑以响应OP的编辑:

如果你看一下 String.replace(char,char)的源代码(在 src 中也可用.zip在你的 JDK 安装目录中 -- 一个专业提示是,每当你想知道某些东西是如何工作的时,就要看看那里),你可以看到它的作用如下:

  • 如果当前字符串中存在一个或多个出现的 ,请复制当前字符串,其中所有出现的 都替换为 。oldCharoldCharnewChar
  • 如果当前字符串中不存在 ,则返回当前字符串。oldChar

所以,是的,创建一个新对象。同样,以下内容成立:"Mississippi".replace('i', '!')String

String s1 = "Mississippi";
String s2 = s1;
s1 = s1.replace('i', '!');
System.out.println(s1); // Prints "M!ss!ss!pp!"
System.out.println(s2); // Prints "Mississippi"
System.out.println(s1 == s2); // Prints "false" as s1 and s2 are two different objects

您现在的功课是看看上面的代码在更改为:)s1 = s1.replace('i', '!');s1 = s1.replace('Q', '!');


1 实际上,可以改变字符串(和其他不可变对象)。它需要反思,非常非常危险,除非你真的有兴趣破坏程序,否则永远不应该使用。


答案 2

引用的对象可以更改,但实际对象本身不能更改。strString

包含字符串的对象无法更改其值,因此它们是不可变的。String"Hello""Help!"

对象的不可变性并不意味着指向该对象的引用不能更改。String

防止引用更改的一种方法是将其声明为:strfinal

final String STR = "Hello";

现在,尝试将另一个分配给 将导致编译错误。StringSTR