考虑下面的例子。

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中字符串的不变性相矛盾吗?有人能给我解释一下不变性的确切概念吗?

编辑:

好的。我现在明白了,但还有一个问题。下面的代码呢:

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!”),并且在replace()方法之后引用str指向不同的对象?


当前回答

或者你可以试试:

public class Tester
{
public static void main(String[] args)
{
 String str = "Mississippi"; 
 System.out.println(str); // prints Mississippi 
 System.out.println(str.hashCode());

 str = str.replace("i", "!"); 
 System.out.println(str); // prints M!ss!ss!pp! 
 System.out.println(str.hashCode());
 }
 }

这将显示hashcode是如何变化的。

其他回答

str引用的对象可以更改,但实际的String对象本身不能更改。

包含字符串“Hello”和“Help!”的String对象不能改变它们的值,因此它们是不可变的。

String对象的不可变性并不意味着指向该对象的引用不能改变。

防止str引用更改的一种方法是将其声明为final:

final String STR = "Hello";

现在,尝试将另一个String赋值给STR将导致编译错误。

str第一次引用的字符串对象没有被改变,你所做的只是让str引用一个新的字符串对象。

Java中的String在Immutable和Final中只是意味着它不能被更改或修改:

案例1:

class TestClass{  
 public static void main(String args[]){  
   String str = "ABC";  
   str.concat("DEF");  
   System.out.println(str);  
 }  
} 

输出:美国广播公司(ABC) 原因:对象引用str没有改变,实际上是一个新对象 在池中创建了“DEF”,它根本没有引用 (也就是失去了)。

案例2:

class TestClass{  
 public static void main(String args[]){  
   String str="ABC";  
   str=str.concat("DEF");  
   System.out.println(str);  
 }  
}  

输出:六边形ABCDEF 原因:在这种情况下,str现在引用一个新对象“ABCDEF” 因此它打印ABCDEF,即前一个str对象“ABC”在池中丢失,没有引用。

虽然java试图忽略它,str只不过是一个指针。这意味着当你第一次写str = "Hello";时,你创建了一个str指向的对象。当你通过写str = "Help!";来重新赋值str时,一个新对象被创建,旧的"Hello"对象在java需要的时候被垃圾收集。

字符串类是不可变的,你不能改变不可变对象的值。 但在String的情况下,如果你改变了String的值,它会在字符串池中创建新的字符串,而不是旧的字符串引用。通过这种方式,字符串是不可变的。 举个例子,

String str = "Mississippi";  
System.out.println(str); // prints Mississippi 

它将创建一个字符串“Mississippi”,并将其添加到字符串池 所以现在str指向密西西比。

str = str.replace("i", "!");  
System.out.println(str); // prints M!ss!ss!pp! 

但经过上述操作, 另一个字符串将被创建"M!ss!ss!pp!" 它将被添加到String池。而且 现在str指向M!ss!ss!pp!而不是密西西比州。

通过这种方式,当你改变string对象的值时,它会创建一个新的对象并将其添加到string池中。

让我们再看一个例子

String s1 = "Hello"; 
String s2 = "World"; 
String s = s1 + s2;

上面的3行代码将向字符串池中添加3个字符串对象。 1)你好 2)世界 3) HelloWorld