String s = new String();
s = s + "abc";
String s = new String();
s = s + "abc";
字符串是不可变的。这意味着String
的实例不可以改变。
你正在将s
变量更改为引用另一个(但仍然不可变的)String
实例。
你的字符串变量并不是字符串本身,它是指向 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
的重写 toString()
方法实现仍将被调用。您需要调用 System.identityHashCode(str)
以获取对象的原始基于身份的哈希码。 - Natixs = s + "abc"
不会将内容附加到 s 对象中,而是创建一个新字符串,其中包含 s 对象中的字符(没有任何字符)和 "abc"。不可变类是那些其方法可以改变其字段的类,例如:
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"
只是为了澄清,当你说 s = s+"abc" 时; 这意味着创建一个新的字符串实例(由 s 和 "abc" 组成),然后将该新的字符串实例分配给 s。因此,s 中的新引用与旧引用不同。
请记住,变量实际上是对某个特定内存位置上的对象的引用。即使您将变量更改为引用不同位置上的新对象,该位置上的对象仍保留在原地。
String s = new String();
创建一个新的、不可变的、空字符串,变量“s”引用它。
s = s+"abc";
创建一个新的、不可变的字符串;空字符串和"abc"的连接,变量"s"现在引用这个新对象。
String s = new String();
String
对象(""
),并且变量s
指向该对象。s = s + "abc";
"abc"
是一个字符串字面量(实际上是一个 String
对象,它会被隐式地创建并保存在字符串池中),以便可以重复使用(因为字符串是不可变的,因此是常量)。但是当你执行 new String()
时完全不同,因为你是显式地创建对象,所以不会最终出现在池中。你可以通过一种叫做 intern 的方法将其放入池中。
因此,s + "abc"
在这个点上,连接空字符串 (""
) 和 "abc"
并不会真正创建一个新的 String
对象,因为最终结果是已经存在于池中的 "abc"
。因此,最终变量 s
将引用池中的字面量 "abc"
。
我相信你们都把这个问题想得太复杂了,这只会让那些试图学习的人感到困惑!
在Java中使对象不可变的主要好处是可以通过引用传递(例如传递给另一个方法或使用赋值运算符分配)而无需担心对象的下游更改会导致当前方法或上下文中出现问题。(这与任何关于对象线程安全性的对话非常不同。)
为了说明这一点,请创建一个应用程序,将一个字符串作为参数传递给一个单独的方法,并在该方法中修改该字符串。在调用方法结束后打印字符串,然后在控制返回到调用方法后再次打印字符串。这两个字符串将具有不同的值,这是因为它们指向不同的内存位置,这是“更改”不可变字符串的直接结果(在幕后创建一个新指针并将其指向新值)。然后创建一个应用程序,执行相同的操作,但使用StringBuffer而不是不可变字符串。(例如,您可以附加到StringBuffer以进行修改。)打印的StringBuffer将具有相同的值,这是因为它是(a)作为Java传递给方法作为参数的所有对象一样被引用传递和(b)可变的。
我希望这能帮助那些正在阅读这个线程并试图学习的人!