はじめに
Java Silverの学習中に、前置演算子・後置演算子の問題でつまずきました。
特に、次のような問題です。
public class Main {
public static void main(String[] args) {
int a = 10;
int b = a++ + a + a-- - a-- + ++a;
System.out.println(b);
}
}
このコードを見たときに、
a++
++a
a--
--a
が、どのタイミングで値を増やしたり減らしたりするのか が分からなくなりました。。。
この記事では、Java Silver対策として、前置演算子・後置演算子の考え方を初心者向けに整理します。
結論
前置・後置の違いは、次のように考えると分かりやすいです。
| 書き方 | 意味 |
|---|---|
a++ |
今の値を使ってから、a を1増やす |
++a |
先に a を1増やしてから、その値を使う |
a-- |
今の値を使ってから、a を1減らす |
--a |
先に a を1減らしてから、その値を使う |
ポイントは、次の2つを分けて考えることです。
式の中で使われる値
計算後に変数へ残る値
特にJava Silverの問題では、変数の最終的な値 だけでなく、式の中で実際に使われる値 を問われることがあります。
つまずきポイント
今回つまずいたポイントは、主にここです。
int b = a++ + a + a-- - a-- + ++a;
一見すると、全部 a を使っているだけに見えます。
しかし、実際にはそれぞれ意味が違います。
a++ // 今のaを使ってから、aを1増やす
a // 今のaをそのまま使う
a-- // 今のaを使ってから、aを1減らす
a-- // 今のaを使ってから、aを1減らす
++a // aを1増やしてから、その値を使う
つまり、同じ a でも、そのタイミングで使われる値が変わる ということです。
コード例
まずは、シンプルな例から確認します。
後置インクリメント:a++
public class Main {
public static void main(String[] args) {
int a = 10;
int b = a++;
System.out.println(b);
System.out.println(a);
}
}
実行結果は次のようになります。
10
11
a++ は、今の値を使ってから1増やす という意味です。
そのため、b には増える前の 10 が入ります。
そのあとで、a は 11 になります。
b = 10
a = 11
前置インクリメント:++a
次に、前置インクリメントを見てみます。
public class Main {
public static void main(String[] args) {
int a = 10;
int b = ++a;
System.out.println(b);
System.out.println(a);
}
}
実行結果は次のようになります。
11
11
++a は、先に1増やしてから、その値を使う という意味です。
そのため、まず a が 10 から 11 になります。
そのあとで、b に 11 が入ります。
a = 11
b = 11
解説
では、今回の問題を見ていきます。
public class Main {
public static void main(String[] args) {
int a = 10;
int b = a++ + a + a-- - a-- + ++a;
System.out.println(b);
}
}
Javaでは、このような式は基本的に左から順番に評価されます。
そのため、左から1つずつ見ていきます。
式を1つずつ置き換える方法
最初の状態です。
a = 10
式は次のとおりです。
a++ + a + a-- - a-- + ++a
左から順番に見ます。
1. a++
a++
a++ は、今の値を使ってから1増やします。
現在の a は 10 です。
そのため、式の中で使われる値は 10 です。
そのあと、a は 11 になります。
使われる値:10
計算後のa:11
2. a
a
現在の a は 11 です。
そのまま 11 が使われます。
使われる値:11
計算後のa:11
3. a--
a--
a-- は、今の値を使ってから1減らします。
現在の a は 11 です。
そのため、式の中で使われる値は 11 です。
そのあと、a は 10 になります。
使われる値:11
計算後のa:10
4. a--
もう一度 a-- です。
a--
現在の a は 10 です。
そのため、式の中で使われる値は 10 です。
そのあと、a は 9 になります。
使われる値:10
計算後のa:9
ここは、式の中では - a-- となっています。
- a--
これは、a-- で使われる値が 10 なので、計算としては - 10 になります。
5. ++a
最後は ++a です。
++a
++a は、先に1増やしてから、その値を使います。
現在の a は 9 です。
まず a が 10 になります。
そのあと、式の中で使われる値も 10 になります。
使われる値:10
計算後のa:10
置き換えた結果
ここまでを式に当てはめると、次のようになります。
a++ + a + a-- - a-- + ++a
これを、実際に使われる値に置き換えると、
10 + 11 + 11 - 10 + 10
になります。
計算すると、
10 + 11 + 11 - 10 + 10 = 32
そのため、出力結果は次のようになります。
32
表で追う方法
このような問題は、暗算で解こうとすると混乱しやすいです。
表で整理するのがおすすめです。
| 順番 | 式の部分 | 式の中で使われる値 | 計算後の a
|
|---|---|---|---|
| 1 | a++ |
10 | 11 |
| 2 | a |
11 | 11 |
| 3 | a-- |
11 | 10 |
| 4 | a-- |
10 | 9 |
| 5 | ++a |
10 | 10 |
式の中で使われる値だけを取り出すと、
10 + 11 + 11 - 10 + 10
になります。
したがって、
b = 32
です。
練習問題
最後に、練習問題です。
問題1
次のコードを実行したとき、何が出力されるでしょうか。
public class Main {
public static void main(String[] args) {
int a = 5;
int b = ++a + a;
System.out.println(b);
}
}
答え
12
++a は、先に a を1増やしてから、その値を使います。
最初、a は 5 です。
++a によって a は 6 になる
そのため、式は次のようになります。
b = 6 + 6
b = 12
最終的に、a は 6、b は 12 です。
問題2
次のコードを実行したとき、何が出力されるでしょうか。
public class Main {
public static void main(String[] args) {
int a = 10;
int result = a++ + a;
System.out.println(result);
}
}
答え
21
a++ は、今の値を使ってから a を1増やします。
最初、a は 10 です。
a++ で使われる値:10
その後の a:11
次の a は、増えたあとの 11 です。
そのため、式は次のようになります。
result = 10 + 11
result = 21
最終的に、a は 11、result は 21 です。
問題3
次のコードを実行したとき、何が出力されるでしょうか。
public class Main {
public static void main(String[] args) {
int n = 10;
System.out.println(n--);
}
}
答え
10
n-- は、今の値を使ってから n を1減らします。
そのため、System.out.println(n--) で出力されるのは、減る前の 10 です。
出力されたあとで、n は 9 になります。
出力される値:10
処理後の n:9
問題4
次のコードを実行したとき、何が出力されるでしょうか。
public class Main {
public static void main(String[] args) {
int x = 1;
x = x++ + ++x;
System.out.println(x);
}
}
答え
4
左から順番に見ていきます。
最初、x は 1 です。
まず、左側の x++ です。
x++ で使われる値:1
その後の x:2
次に、右側の ++x です。
++x は、先に x を1増やしてから、その値を使います。
++x によって x は 3 になる
++x で使われる値:3
そのため、式は次のようになります。
x = 1 + 3
x = 4
最終的に、x の値は 4 です。
まとめ
前置演算子・後置演算子は、次のように覚えると分かりやすいです。
| 書き方 | 考え方 |
|---|---|
a++ |
使ってから増える |
++a |
増えてから使う |
a-- |
使ってから減る |
--a |
減ってから使う |
長い式が出てきたら、暗算で一気に解こうとせず、左から順番に表で追うとミスを減らせます。
参考文献
この記事は以下を参考に記載しました。
徹底攻略Java SE 17 Silver問題集