考虑下面的例子。

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指向不同的对象?


当前回答

Use:

String s = new String("New String");
s.concat(" Added String");
System.out.println("String reference -----> "+s); // Output: String reference -----> New String

如果你看到这里我使用concat方法来改变原始字符串,即“新字符串”与字符串“添加的字符串”,但我仍然得到了输出,因此它证明了你不能改变string类对象的引用,但如果你通过StringBuilder类做这件事,它将工作。它列在下面。

StringBuilder sb = new StringBuilder("New String");
sb.append(" Added String");
System.out.println("StringBuilder reference -----> "+sb);// Output: StringBuilder reference -----> New String Added String

其他回答

如果HELLO是你的字符串,那么你不能把HELLO改成HILLO。这个性质叫做不可变性。

你可以有多个指针字符串变量指向HELLO字符串。

但是如果HELLO是char Array,那么你可以将HELLO改为HILLO。例如,

char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this

编程语言具有不可变的数据变量,因此可以作为键、值对中的键使用。

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

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

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

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

final String STR = "Hello";

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

字符串是不可变的。这意味着我们只能改变引用。


String a = "a";
System.out.println("String a is referencing to "+a); // Output: a

a.concat("b");
System.out.println("String a is referencing to "+a); // Output: a

a = a.concat("b");
System.out.println("String a has created a new reference and is now referencing to "+a); // Output: ab

让我们把它分成几个部分

String s1 = "hello";

此语句创建包含hello的字符串并占用内存空间,即在常量字符串池中,并将其分配给引用对象s1

String s2 = s1;

这条语句将相同的字符串hello赋值给新引用s2

         __________
        |          |
s1 ---->|  hello   |<----- s2
        |__________| 

两个引用都指向相同的字符串,因此输出相同的值,如下所示。

out.println(s1);    // o/p: hello
out.println(s2);    // o/p: hello

虽然String是不可变的,但可以赋值,因此s1现在将引用新的值堆栈。

s1 = "stack";    
         __________
        |          |
s1 ---->|  stack   |
        |__________|

但是指向hello的s2对象呢它还是原来的样子。

         __________
        |          |
s2 ---->|  hello   |
        |__________|

out.println(s1);    // o/p: stack
out.println(s2);    // o/p: hello

由于字符串是不可变的,Java虚拟机不允许我们通过它的方法修改字符串s1。它将在池中创建所有新的String对象,如下所示。

s1.concat(" overflow");

                 ___________________
                |                   |
s1.concat ----> |  stack overflow   |
                |___________________|

out.println(s1);    // o/p: stack
out.println(s2);    // o/p: hello
out.println(s1.concat); // o/p: stack overflow

注意,如果String将是可变的,那么输出将是

out.println(s1);    // o/p: stack overflow

现在,您可能会感到惊讶,为什么String需要修改concat()这样的方法。下面的代码片段将消除您的困惑。

s1 = s1.concat(" overflow");

这里我们将修改后的string值赋值给s1引用。

         ___________________
        |                   |
s1 ---->|  stack overflow   |
        |___________________|


out.println(s1);    // o/p: stack overflow
out.println(s2);    // o/p: hello

这就是为什么Java决定将String作为最终类,否则任何人都可以修改和改变String的值。 希望这能有所帮助。

字符串类是不可变的,你不能改变不可变对象的值。 但在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