Stringの不変性を理解する
Stringの不変性は、変数を書き換えられないという意味ではありません。文字列オブジェクトの内容、参照を保持する変数、メソッドが返す値を分けると、連結や置換後に何が残るかを説明できます。
この単元で学ぶこと
- オブジェクトの不変性と変数の再代入を区別する
- 共有参照と文字列操作の結果を追う
- final・配列・Stringの関係を説明する
本文解説
変わらないのはオブジェクトの内容 String a="cat";String b=a;では二つの変数が同じ文字列を参照します。a=a.concat("s");の後、aはcatsを表す文字列へ変わりますがbはcatのままです。catの内容をその場でcatsへ書き換えたのではありません。この性質によって、文字列を他の処理へ渡しても内容を勝手に編集されません。
戻り値を無視するとどうなるか String s="Java";s.substring(1);System.out.print(s);はJavaです。substringは範囲avaを表す値を返しますが、sへの代入はありません。System.out.print(s.substring(1));ならavaを表示します。変換メソッドを呼んだ行ごとに、返り値の行き先を確認します。
参照の再代入は可能 String s="A";s="B";は有効です。変数が参照する先を変えただけで、Aという文字列をBへ書き換えたわけではありません。s+="C";は連結した結果をsへ戻す代入を含み、sはBCになります。+=はStringの内容を可変にする特別な機能ではありません。
finalが制限するもの final String s="A";では変数sへの再代入が禁止され、s="B";やs+="B";はコンパイルエラーです。一方、s.concat("B")を呼んで返り値を別の変数へ保存することはできます。Stringの不変性はfinalを付けなくても成立します。finalは変数、不変性はオブジェクトの性質です。
配列の要素は別の変数 final String[] a={"red"};a[0]="blue";は有効です。finalが固定するのは配列を参照する変数aであり、要素a[0]の参照ではありません。String[] b=a;なら同じ配列を共有するのでb[0]もblueになります。配列の可変性と、その要素が参照するStringの不変性を二段階で考えます。
連続操作の中間値 String s=" a-b ";String t=s.trim().replace('-',':');では、trimの結果a-bに置換を適用してtはa:bになります。元のsは両端に空白を持ったままです。連鎖は一時的な結果を次の呼出し先に使います。最後に代入しない限り、元の変数が新しい値を参照することはありません。
char配列からの作成 char[] a={'c','a','t'};String s=new String(a);a[0]='b';の後もsはcatです。コンストラクタが文字列の内容として取り込んだ値は、元の配列を後から変更しても変わりません。逆にs.toCharArray()で得た配列を編集してもsは変化しません。可変データとの境界でも不変性を確認できます。
必ず別オブジェクトとは限らない 不変性が保証するのは元の文字の並びが変わらないことです。内容が変わらない操作で元のオブジェクトを返す場合もあります。たとえばs.concat("")はsを返す仕様です。すべてのStringメソッドが必ず新規生成する、と暗記せず、内容比較にはequalsを使い、参照同一性が必要な場合だけ仕様を確認します。
図解
重要ポイント
- 変換結果の返り先を追う。
- 再代入は元のStringの変更ではない。
- finalは配列要素まで固定しない。
- 不変性から新規オブジェクト生成の有無は一般化できない。
間違えやすい点
- concatやreplaceの戻り値を捨てない。
- 同じ配列を共有している場合は要素変更が双方から見える。
- finalと不変を同義にしない。
用語解説
- 不変
- 生成後にオブジェクトの内容を変更できない性質。
- 再代入
- 変数に別の値を保存すること。
- 参照共有
- 複数の変数が同じオブジェクトを指す状態。
関連教材
参考資料
教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。
- https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html
- https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuilder.html
- https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.10.5
- https://docs.oracle.com/javase/specs/jls/se17/html/jls-15.html#jls-15.21.3
確認問題の出題・採点や学習履歴の保存にはログインが必要です。