いくつかの部分に分けましょう
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
けれども文字列がある不変ので、割り当てが可能することができs1は今、新しい値を参照しますスタック。
s1 = "stack";
__________
| |
s1 ---->| stack |
|__________|
しかし、こんにちはを指す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を最終クラスに決定しました。そうでなければ、誰でもstringの値を変更および変更できます。これが少し役立つことを願っています。