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)可变的。
我希望这能帮助正在阅读这个主题并试图学习的人们!