让我们把它分成几个部分。
String s1 = "hello";
这个语句创建了一个字符串,包含hello,并在内存中占用空间,即在常量字符串池中,并将其分配给引用对象s1
String s2 = s1;
该语句将字符串
hello分配给新引用
s2。
__________
| |
s1 ---->| hello |<----- s2
|__________|
两个引用都指向同一个字符串,因此输出结果如下。
out.println(s1)
out.println(s2)
虽然 String 是不可变的,但是赋值是可能的,所以 s1 现在将引用新值 stack。
s1 = "stack";
__________
| |
s1 ---->| stack |
|__________|
那么,指向 hello 的 s2 对象将保持不变。
__________
| |
s2 ---->| hello |
|__________|
out.println(s1); // o/p: stack
out.println(s2); // o/p: hello
由于String是不可变的,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");
在这里,我们将修改后的字符串值分配回s1引用。
___________________
| |
s1 ---->| stack overflow |
|___________________|
out.println(s1); // o/p: stack overflow
out.println(s2); // o/p: hello
这就是为什么Java决定将
String设为final类,否则任何人都可以修改和更改字符串的值。
希望这能有所帮助。