インクリメントがどのように扱われるか
投稿2回目にしていきなりAndroidのゲーム開発とは違ったことを書いていきます。
とはいえ、まったく関係ないことはなく、AndroidゲームプログラミングAtoZのサンプルコードを眺めていた時に疑問に思ったことです。
以下のコードを御覧ください。
public class WhileTest {
public static void main(String[] args) {
int[] num = {1, 2, 3, 4};
int i = 0;
System.out.print(num[i++] + ":i = " + i + ",");
System.out.print(num[i++] + ":i = " + i + ",");
System.out.print(num[i++] + ":i = " + i + ",");
System.out.print(num[i++] + ":i = " + i +"\n");
i = 0;
while(i <= 3) {
System.out.print(num[i++] + ":i = " + i + ",");
}
System.out.println();
i = 0;
while(i <= 3) {
System.out.print(num[i] + ":i = " + i +",");
i++;
}
System.out.println();
i = 0;
while(++i <= 3) {
System.out.print(num[i] + ":i = " + i + ",");
}
System.out.println();
i = 0;
while(i++ <= 3) {
System.out.print(num[i] + ":i = " + i + ",");
}
System.out.println();
}
}
笑えるくらい簡単なコードです。
これで何を調べたかったのかというと、配列のインデックス、またはwhileブロックで異なる条件を指定してどのように結果が出力されるのか、ということです。
それぞれ違った形でiをインクリメントしていき、num[i]とiをSystem.out.printで出力していく、といった手順で調べてみました。
出力結果は以下のようになりました。
1:i = 1,2:i = 2,3:i = 3,4:i = 4
1:i = 1,2:i = 2,3:i = 3,4:i = 4,
1:i = 0,2:i = 1,3:i = 2,4:i = 3,
2:i = 1,3:i = 2,4:i = 3,
2:i = 1,3:i = 2,4:i = 3,Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
at WhileTest.main(WhileTest.java:36)
正直予想外の結果です。
とりあえず順番に見て行きましょう。
まずはnum[i++]の形で指定した場合の出力結果です。
私の中では、num[1],num[2],num[3],num[4](ArrayIndexOutOfBoundsException)、iの中身も同様に1, 2, 3, 4となっているのを期待していたのですが、実際はきれいにnum[0],num[1],num[2],num[3]の順に出力されました。
しかし、その後のiの中身を調べると1, 2, 3, 4と私の予想通りの結果です。
これはどういうことなのでしょうか。
とりあえず置いておいて、次の行の結果を見てみましょう。
この行は、whileブロックの中の配列のインデックスiをインクリメントした場合の出力結果です。
この時の私の予想と結果は上記と同じです。
次の行です。
whileの条件でi <= 3を指定し、whileブロックの最後にiをインクリメントした場合です。
これは予想通りです。しっかりnum[i]のiと、その次のiの中身が一致しています。
次はその下の行です。
これはwhileの条件で++i <= 3と指定した時のものです。いわゆる前置インクリメントを使用しました。
この時の結果は、num[1]からnum[3]までを出力してくれました。iの中身もnumのインデックスと同じ結果が出力されています。
最後に、whileの条件でi++ <= 3を指定したときです。これは後置インクリメントを使用しています。
numの出力は前置インクリメントを使用した時と同じで、iの中身も同様ですが、最後に例外を出していることから、この条件の時は、iは4まで増えてしまっていいることが分かります。
簡単に言うと前置インクリメントは最初に1増やす、後置インクリメントは後から1増やすということらしいです。つまり、前置インクリメントを使用したwhileブロックでは、iを1増やしてから3と比較していて、後置インクリメントを使用したwhileブロックでは、iと3を比較してからiを1増やしたので、例外が出てしまった、ということでしょうか。
後置、前置インクリメントについてもう少し調べるために、配列のインデックスをインクリメントした所を前置インクリメントに変えてみました。
public class WhileTest {
public static void main(String[] args) {
int[] num = {1, 2, 3, 4};
int i = 0;
System.out.print(num[++i] + ":i = " + i + ",");
System.out.print(num[++i] + ":i = " + i + ",");
System.out.print(num[++i] + ":i = " + i + ",");
System.out.print(num[++i] + ":i = " + i +"\n");
}
}
結果は、
2:i = 1,3:i = 2,4:i = 3,Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
at WhileTest.main(WhileTest.java:10)
どうやら前置インクリメントを使用した場合は、私の予想通りの結果を出してくれるようです。
つまりこういうことでしょうか、
配列内のインデックスを後置インクリメントした場合、
配列のインデックスを決定してからiがインクリメントされる
配列内のインデックスを前置インクリメントした場合、
インデックスのiをインクリメントしてから配列が決定される
このような違いが生じていると推測されます。
しかし、テストの結果から自分なりに考えたものなので、違う部分もあるかもしれませんね。
こういったことはC言語あたりを学べばしっかり理解できるようになるのでしょうか……。
このような細かい仕様などは、今後プログラミングを続けていく上で重要になってきそうですね。