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を使い、参照同一性が必要な場合だけ仕様を確認します。

図解

元の文字列と再代入後の参照
変数の参照先が変わっても、元のcatの内容は変わらない。

重要ポイント

  • 変換結果の返り先を追う。
  • 再代入は元のStringの変更ではない。
  • finalは配列要素まで固定しない。
  • 不変性から新規オブジェクト生成の有無は一般化できない。

間違えやすい点

  • concatやreplaceの戻り値を捨てない。
  • 同じ配列を共有している場合は要素変更が双方から見える。
  • finalと不変を同義にしない。

用語解説

不変
生成後にオブジェクトの内容を変更できない性質。
再代入
変数に別の値を保存すること。
参照共有
複数の変数が同じオブジェクトを指す状態。

関連教材

参考資料

教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。

確認問題の出題・採点や学習履歴の保存にはログインが必要です。