for・拡張forのコードトレース

基本forと拡張forを選び分ける演習です。元の配列、各回の変数、最終出力を分けて書き、代入先がどこかを確かめます。

この単元で学ぶこと

  • 拡張forで配列を走査する
  • ループ変数への代入と配列要素の更新を区別する
  • 添字が必要な処理で基本forを選ぶ

本文解説

集計の準備 int[] a={3,5,7}; int sum=0; for(int x:a){sum+=x;}は15です。添字を足す基本forのsum+=iなら0+1+2=3になり、要素を足す処理とは違います。値と位置を二列に分けて追います。

倍率を変数へ代入 for(int x:a){x*=2;}だけでは元のaは{3,5,7}のままです。本体でxを表示すると6、10、14ですが、ループ後の配列を表示すると元の値です。同じ表示位置で比較することが必要です。

配列を実際に更新 for(int i=0;i<a.length;i++){a[i]*=2;}なら要素は{6,10,14}になります。配列更新を拡張forの変数更新へ機械的に書き換えると結果が変わります。結果を確かめるループは更新後に置きます。

参照先と再代入を続ける StringBuilder[] a={new StringBuilder("A")}; for(StringBuilder x:a){x.append("B");x=new StringBuilder("C");x.append("D");}ではa[0]はABです。最初のappendは共有先、再代入後のappendは新しいオブジェクトへ作用します。

二つの要素が同じ対象を指す StringBuilder b=new StringBuilder("A"); StringBuilder[] a={b,b}; for(StringBuilder x:a){x.append("X");}ではbはAXXです。配列要素数は2でも対象オブジェクトは一つです。各回でその同じ対象を変更します。

nullを要素として含む String[] a={"A",null,"B"}; int n=0; for(String x:a){if(x!=null)n+=x.length();}は2です。nullを除く条件がメソッド呼出しより前にあります。配列参照全体がnullなら、この本体の条件まで到達できません。

入れ子の走査 int[][] a={{1,2},{3}}; int s=0; for(int[] row:a){for(int x:row){s+=x;}}は6です。外側は行配列、内側はint値を受け取ります。行ごとの長さは異なっていてよく、空の行なら内側だけ0回です。

照合の手順 要素を足す基本forと拡張forを別々に動かし、同じ配列なら同じ集計になることを確認します。その後、変数への代入、配列更新、可変対象の変更を一つずつ追加します。型が違う例はコンパイル結果から先に分類します。

図解

要素を受け取った後の代入先
要素のコピーは、参照先オブジェクトのコピーを意味しない。

重要ポイント

  • 拡張forの変数は要素であり添字ではない。
  • 変数への代入だけでは元の配列要素を置き換えない。
  • 参照先の可変オブジェクトは変更できる。
  • 空配列とnull配列を区別する。

間違えやすい点

  • x++でint配列を更新したつもりにならない。
  • Stringへの再代入とStringBuilderの変更を混同しない。
  • 位置・逆順が必要な処理を拡張forだけで無理に書かない。

用語解説

拡張for
配列やIterableから要素を順次受け取る繰返し。
ループ変数
各回の要素を受け取る本体内の変数。
参照
オブジェクトを指し示す値。
可変オブジェクト
生成後に内部状態を変更できるオブジェクト。

関連教材

参考資料

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

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