考虑以下示例。
String str = new String(); str = "Hello"; System.out.println(str); //Prints Hello str = "Help!"; System.out.println(str); //Prints Help!
现在,在 Java 中,String 对象是不可变的。那么为什么可以为对象str分配值“Help!”。这不是与 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!”),并且引用在方法str之后指向不同的对象replace()?
replace()
str不是对象,它是对对象的引用。"Hello"并且"Help!"是两个不同的String对象。因此,str 指向 一个字符串。您可以更改它所 指向的 内容,但不能更改它所 指向的 内容。
"Hello"
"Help!"
String
以这段代码为例:
String s1 = "Hello"; String s2 = s1; // s1 and s2 now point at the same string - "Hello"
现在,我们无能为力1会s1影响 的值s2。它们引用同一个对象 - 字符串"Hello"- 但该对象是不可变的,因此无法更改。
s1
s2
如果我们这样做:
s1 = "Help!"; System.out.println(s2); // still prints "Hello"
在这里,我们看到了改变对象和更改引用之间的区别。仍然指向与我们最初设置指向s2的对象相同的对象。s1设置s1为"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) 的源代码(也可以在 JDK 安装目录中的 src.zip 中找到——一个专业提示是,只要您想知道某些东西是如何工作的,就去那里看看)您会看到什么它确实如下:
oldChar
newChar
所以是的,"Mississippi".replace('i', '!')创建一个新String对象。同样,以下成立:
"Mississippi".replace('i', '!')
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', '!');:)
s1 = s1.replace('i', '!');
s1 = s1.replace('Q', '!');
1实际上, 可以 改变字符串(和其他不可变对象)。它需要反射,非常非常危险,除非你真的有兴趣破坏程序,否则永远不应该使用它。