Java不可变字符串混乱

时间:2012-01-19 23:03:31

标签: java

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

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

8 个答案:

答案 0 :(得分:8)

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

您正在更改s 变量以引用其他(但仍然不可变的)String实例。

答案 1 :(得分:7)

您的字符串变量不是字符串。它是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

答案 2 :(得分:2)

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

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

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

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

答案 3 :(得分:1)

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

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

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

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"

答案 4 :(得分:0)

   String s = new String();  

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

   s = s+"abc";              

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

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

String s = new String();

创建一个空的String对象("")。变量s引用该对象。

s = s + "abc";

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

所以,s + "abc"因为此时和空字符串("")和"abc"的连接并没有真正创建新的String对象,因为最终结果为{ {1}}已经在池中。因此,最后变量"abc"将引用池中的文字s

答案 7 :(得分:-2)

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

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

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

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