Java不可变字符串混乱

如果String在Java中是不可变的,那么我们如何写为:

 String s = new String(); s = s + "abc"; 

您的字符串变量不是字符串。 它是String实例的参考。

你自己看:

 String str = "Test String"; System.out.println( System.identityHashCode(str) ); // INSTANCE ID of the string str = str + "Another value"; System.out.println( System.identityHashCode(str) ); // Whoa, it's a different string! 

str变量指向的实例是单独不可变的,但该变量可以指向您想要的任何String实例。

如果您不希望将str重新分配给指向不同的字符串实例,请将其声明为final:

 final String str = "Test String"; System.out.println( System.identityHashCode(str) ); // INSTANCE ID of the string str = str + "Another value"; // BREAKS HORRIBLY 

字符串不可变的。
这意味着String实例无法更改。

您正在更改s 变量以引用另一个(但仍然是不可变的) String实例。

第一个答案是绝对正确的。 你应该把它标记为已回答。

s = s+"abc"不会附加到s对象。 它创建一个新的字符串,其中包含s对象(其中没有)和“abc”中的字符。

如果字符串是可变的。 它会有像append()这样的方法以及StringBuilder和StringBuffer上的其他类似的变异方法。

Josh Bloch的有效Java对不可变对象及其价值进行了很好的讨论。

不可变类是那些方法可以改变其字段的类,例如:

 Foo f = new Foo("a"); f.setField("b"); // Now, you are changing the field of class Foo 

但是在不可变类中,例如String,一旦创建它就无法更改对象,但当然 ,您可以将引用重新分配给另一个对象。 例如:

 String s = "Hello"; s.substring(0,1); // s is still "Hello" s = s.substring(0,1); // s is now referring to another object whose value is "H" 
  String s = new String(); 

创建一个新的,不可变的空字符串,变量“s”引用它。

  s = s+"abc"; 

创建一个新的,不可变的字符串; 空字符串和“abc”的串联,变量“s”现在引用这个新对象。

只是为了澄清,当你说s = s +“abc”时; 这意味着,创建一个新的String实例(由s和“abc”组成),然后将新的String实例分配给s。 所以s中的新引用与旧引用不同。

请记住,变量实际上是对某个特定内存位置的对象的引用。 即使您更改变量以引用其他位置的新对象,该位置的对象也会保留在该位置。

 String s = new String(); 

创建一个空String对象( "" )。 变量s指的是那个对象。

 s = s + "abc"; 

"abc"是一个字符串文字(它只是一个String对象,它是隐式创建并保存在字符串池中),因此可以重用它(因为字符串是不可变的,因此是常量)。 但是当你做new String()完全不同,因为你明确地创建了对象,所以不会在池中结束。 你可以通过一个叫做实习的东西扔进游泳池。

所以, s + "abc"因为此时串联和空字符串( "" )和"abc"并不真正创建一个新的String对象,因为最终结果是已经在池中的"abc" 。 所以,最后变量s将引用池中的文字"abc"

我相信你们所做的一切都比它需要的要复杂得多,而这只会让想要学习的人感到困惑!

使对象在Java中不可变的主要好处是它可以通过引用传递(例如,传递给另一个方法或使用赋值运算符分配),而不必担心对象的下游更改导致当前方法或上下文中的问题。 (这与关于对象的线程安全性的任何对话非常不同。)

为了说明,创建一个将String作为参数传递给单独方法的应用程序,并修改该方法中的String。 在被调用方法的末尾打印String,然后在控制返回到调用方法之后。 字符串将具有不同的值,这是因为它们指向不同的内存位置,这是“更改”不可变String的直接结果(创建新指针并将其指向幕后的新值)。 然后创建一个执行相同操作的应用程序,除了StringBuffer,它不是不可变的。 (例如,您可以附加到StringBuffer来修改它。)打印的StringBuffers将具有相同的值,这是因为它是(a)通过引用传递,因为Java将所有对象作为参数传递给方法, (b)可变的。

我希望这能帮助正在阅读这个主题并试图学习的人们!