Java Silver 演算子と制御構造 問題

ゆめさくが作った練習問題です。本試験の問題ではありません。

演算子と制御構造の問題を1⁠4問、小分野ごとにまとめました。選ぶと、その場で正誤と解説が出ます。

ログインなしで解けます。答えはこのブラウザの中だけに残り、どこにも送りません。

この分野の小分野

  • 演算子と分岐と switch(7問)
  • 繰り返しと break と continue(7問)

演算子と制御構造の問題

14 問

選ぶと、すぐに正誤と解説が出ます。選んだ答えは変えられません。

  1. 演算子と分岐と switch

    問 1次のコードをコンパイルして実行したときの結果として正しいものはどれですか。

    public class Main {
        public static void main(String[] args) {
            int r = -7 + 20 % -6 * 2 + 9 / -2;
            System.out.println(r);
        }
    }
  2. 問 2次のコードをコンパイルして実行したときの結果として正しいものはどれですか。

    public class Main {
        public static void main(String[] args) {
            int[] a = {10, 20, 30};
            int i = 0;
            a[i++] = a[i] + i++;
            System.out.println(a[0] + " " + a[1] + " " + i);
        }
    }
  3. 問 3次のコードをコンパイルして実行したときの結果として正しいものはどれですか。

    public class Main {
        public static void main(String[] args) {
            byte b = 120;
            b += 10;
            short s = 7;
            s *= 1.5;
            int n = 5;
            n /= 2.0;
            System.out.println(b + " " + s + " " + n);
        }
    }
  4. 問 4次のコードをコンパイルして実行したときの結果として正しいものはどれですか。

    public class Main {
        public static void main(String[] args) {
            int a = 3, b = 0;
            if (a > 2 || ++b > 0)
                if (b > 0)
                    System.out.print("X");
            else
                System.out.print("Y");
            System.out.print(b);
        }
    }
  5. 問 5次のコードをコンパイルして実行したときの結果として正しいものはどれですか。

    public class Main {
        public static void main(String[] args) {
            int n = 5;
            switch (n) {
                case 1:
                    System.out.print("A");
                default:
                    System.out.print("D");
                case 2:
                    System.out.print("B");
                    break;
                case 3:
                    System.out.print("C");
            }
        }
    }
  6. 問 6次のコードをコンパイルしたときの結果として正しいものはどれですか。

    public class Main {
        public static void main(String[] args) {
            String s = "ab";
            final String A = "a";
            String b = "b";
            switch (s) {
                case A:              // (A)
                    System.out.print(1);
                    break;
                case b:              // (B)
                    System.out.print(2);
                    break;
                case A + "b":        // (C)
                    System.out.print(3);
                    break;
                case "x" + "y":      // (D)
                    System.out.print(4);
                    break;
            }
        }
    }
  7. 問 7次のコードをコンパイルして実行したときの結果として正しいものはどれですか。

    public class Main {
        public static void main(String[] args) {
            int n = 2;
            String s = switch (n) {
                case 1 -> "one";
                case 2 -> {
                    String t = "tw";
                    yield t + "o";
                }
            };
            System.out.println(s);
        }
    }
  8. 繰り返しと break と continue

    問 8次のコードをコンパイルして実行したときの結果として正しいものはどれですか。

    public class Main {
        public static void main(String[] args) {
            int i = 0;
            do {
                if (i == 0) {
                    i = 10;
                    continue;
                }
                System.out.print("X");
            } while (i < 5);
            System.out.print(i);
        }
    }
  9. 問 9for 文の書き方として、コンパイルできるものはどれですか。

  10. 問 10次のコードをコンパイルしたときの結果として正しいものはどれですか。

    public class Main {
        public static void main(String[] args) {
            int n = 0;
            block: {
                n++;
                if (n > 0) break block;       // (A)
                n = 10;
            }
            for (int i = 0; i < 3; i++) {
                if (i == 1) continue;         // (B)
                n += i;
            }
            check: {
                if (n > 2) continue check;    // (C)
            }
            System.out.print(n);
        }
    }
  11. 問 11次のコードをコンパイルして実行したときの結果として正しいものはどれですか。

    public class Main {
        public static void main(String[] args) {
            int n = 3;
            while (n-- > 0) {
                System.out.print(n);
            }
            System.out.print("/" + n);
        }
    }
  12. 問 12次のコードをコンパイルして実行したときの結果として正しいものはどれですか。

    public class Main {
        public static void main(String[] args) {
            int i = 0;
            loop:
            while (true) {
                switch (i++) {
                    case 0:
                        System.out.print("A");
                        break;
                    case 1:
                        System.out.print("B");
                        continue loop;
                    default:
                        System.out.print("C");
                        break loop;
                }
                System.out.print("-");
            }
            System.out.print(i);
        }
    }
  13. 問 13次のコードをコンパイルしたときの結果として正しいものはどれですか。

    public class Main {
        public static void main(String[] args) {
            int n = 0;
            while (true) {
                if (++n > 2) break;
            }
            System.out.print(n);        // (A)
            do {
                n++;
            } while (false);
            System.out.print(n);        // (B)
            while (true) {
                n++;
            }
            System.out.print(n);        // (C)
        }
    }
  14. 問 14for (;;) のように for 文の条件式を省略したときの動きとして正しいものはどれですか。

14 問中 0 問に答えました

解説の一覧

解いたあとに読み返せるよう、全問の解説を並べています。問いを開くと解説が出ます。

演算子と分岐と switch

問1次のコードをコンパイルして実行したときの結果として正しいものはどれですか。
public class Main {
    public static void main(String[] args) {
        int r = -7 + 20 % -6 * 2 + 9 / -2;
        System.out.println(r);
    }
}

正解は「-7」です。*、/、% は + より優先順位が高く、同じ優先順位どうしは左から順に結び付きます。式は -7 + ((2⁠0 % -6) * 2) + (9 / -2) と読みます。% の結果の符号は割られる数 (左側) の符号に合わせるので 2⁠0 % -6 は 2、2 * 2 は 4 です。整数の割り算は 0 の方向へ切り捨てるので 9 / -2 は -4 です。合計は -7 + 4 - 4 で -7 です。「-1⁠9」は % の符号を割る数 (右側) に合わせて 2⁠0 % -6 を -4 とした値です。「-8」は 9 / -2 を小さい方向へ切り下げて -5 とした値です。「-5」は優先順位を無視して左から順に計算した値です。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠5.html#jls-⁠1⁠5.1⁠7.3

問2次のコードをコンパイルして実行したときの結果として正しいものはどれですか。
public class Main {
    public static void main(String[] args) {
        int[] a = {10, 20, 30};
        int i = 0;
        a[i++] = a[i] + i++;
        System.out.println(a[0] + " " + a[1] + " " + i);
    }
}

正解は「2⁠1 2⁠0 2」です。二項演算子と代入では、左側が右側より先に評価されます。代入 a[i++] = ... では、まず左側の a[i++] が評価され、書き込む先は a[0] に決まり、i は 1 になります。次に右側の a[i] + i++ を評価します。このとき i は 1 なので a[1] の 2⁠0 を読み、i++ は今の値 1 を返してから i を 2 にします。右側は 2⁠1 で、a[0] に 2⁠1 が入ります。a[1] は 2⁠0 のまま、i は 2 なので「2⁠1 2⁠0 2」です。「1⁠0 1⁠0 2」は右側を先に評価したときの値です。「1⁠1 2⁠0 2」は a[i] を i が 0 のときに読んだと考えた値です。「2⁠1 2⁠0 1」は右側の i++ による増加を見落とした値です。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠5.html#jls-⁠1⁠5.7.1

問3次のコードをコンパイルして実行したときの結果として正しいものはどれですか。
public class Main {
    public static void main(String[] args) {
        byte b = 120;
        b += 10;
        short s = 7;
        s *= 1.5;
        int n = 5;
        n /= 2.0;
        System.out.println(b + " " + s + " " + n);
    }
}

正解は「-1⁠2⁠6 1⁠0 2」です。複合代入 E1 op= E2 は E1 = (T)((E1) op (E2)) と同じ意味で、T は左側の変数の型です。キャストが暗黙に入るので、b = b + 1⁠0 なら出るコンパイルエラーが b += 1⁠0 では出ません。b += 1⁠0 は int の 1⁠3⁠0 を byte にキャストし、byte の範囲 -1⁠2⁠8 から 1⁠2⁠7 を超えた分が回り込んで -1⁠2⁠6 になります。s *= 1.5 は 1⁠0.5 を short にキャストし、小数部が切り捨てられて 1⁠0 です。n /= 2.0 は 2.5 を int にして 2 です。「1⁠3⁠0 1⁠0 2」は byte の範囲を考えていません。「-1⁠2⁠6 1⁠1 3」はキャストで四捨五入されると考えた値です。「コンパイルエラーになる」は、複合代入に暗黙のキャストが入ることを見落としています。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠5.html#jls-⁠1⁠5.2⁠6.2

問4次のコードをコンパイルして実行したときの結果として正しいものはどれですか。
public class Main {
    public static void main(String[] args) {
        int a = 3, b = 0;
        if (a > 2 || ++b > 0)
            if (b > 0)
                System.out.print("X");
        else
            System.out.print("Y");
        System.out.print(b);
    }
}

正解は「Y0」です。else は、波括弧が無いとき、結び付ける候補のうち最も内側の if に属します。字下げは意味を持ちません。このコードの else は外側の if ではなく、内側の if (b > 0) の else です。また || は左側が true なら右側を評価しません。a > 2 が true なので ++b は実行されず、b は 0 のままです。外側の条件は true なので内側の if に進み、b > 0 は false なので else の Y を出力し、最後に b の 0 を出力して「Y0」です。「X1」と「Y1」は || の右側の ++b も実行されると考えた結果です。「0」は else が外側の if に付くと考え、内側の if で何も出力されないとした結果です。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠4.html#jls-⁠1⁠4.5

問5次のコードをコンパイルして実行したときの結果として正しいものはどれですか。
public class Main {
    public static void main(String[] args) {
        int n = 5;
        switch (n) {
            case 1:
                System.out.print("A");
            default:
                System.out.print("D");
            case 2:
                System.out.print("B");
                break;
            case 3:
                System.out.print("C");
        }
    }
}

正解は「DB」です。default は switch ブロックのどこに書いてもよく、最後でなくてもコンパイルできます。n は 5 で、case 1、case 2、case 3 のどれとも一致しないので default の位置から実行が始まります。コロンを使う形の switch 文は、一致したラベルのあとの文を break まで順に実行します (フォールスルー)。D を出力したあと、続く case 2 の B も出力し、break で switch を抜けます。結果は「DB」です。「D」は default の処理だけで止まると考えた結果です。「DBC」は break を見落とした結果です。「コンパイルエラーになる」は default を途中に書けないと考えた答えです。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠4.html#jls-⁠1⁠4.1⁠1.3

問6次のコードをコンパイルしたときの結果として正しいものはどれですか。
public class Main {
    public static void main(String[] args) {
        String s = "ab";
        final String A = "a";
        String b = "b";
        switch (s) {
            case A:              // (A)
                System.out.print(1);
                break;
            case b:              // (B)
                System.out.print(2);
                break;
            case A + "b":        // (C)
                System.out.print(3);
                break;
            case "x" + "y":      // (D)
                System.out.print(4);
                break;
        }
    }
}

正解は「(B) の行でコンパイルエラーになる」です。case に書く値は、定数式か enum の定数でなければなりません。(B) の b は final が付いていない普通の変数なので定数式ではなく、「定数の文字列の式が必要」というエラーになります。(A) の A は final で文字列リテラルで初期化されているので定数変数で、定数式として書けます。(C) の A + "b" も、定数変数とリテラルの連結なので定数式です。(D) の "x" + "y" もリテラルどうしの連結なので定数式です。switch のセレクタ式に使える型は char、byte、short、int と、それらのラッパー型、String、enum で、String の一致は equals で調べます。String を使うこと自体は問題ありません。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠4.html#jls-⁠1⁠4.1⁠1.1

問7次のコードをコンパイルして実行したときの結果として正しいものはどれですか。
public class Main {
    public static void main(String[] args) {
        int n = 2;
        String s = switch (n) {
            case 1 -> "one";
            case 2 -> {
                String t = "tw";
                yield t + "o";
            }
        };
        System.out.println(s);
    }
}

正解は「コンパイルエラーになる」です。switch 式は、どの値が来ても必ず値を返せなければなりません。セレクタが enum でないときは default がちょうど 1 つ必要で、無ければコンパイルエラーです。このコードの switch 式は int の n を調べていますが、case 1 と case 2 しか無く default が無いので、String s = switch (n) の行で「switch 式がすべての入力を扱っていない」というエラーになります。アロー形式のブロックでは yield で値を返す書き方は正しく、この部分は問題ありません。「two」は n が 2 なので実行できると考えた答えです。「null」は一致しないときに null になると考えた答え、「実行時に例外が出る」は網羅を実行時に調べると考えた答えです。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠5.html#jls-⁠1⁠5.2⁠8.1

繰り返しと break と continue

問8次のコードをコンパイルして実行したときの結果として正しいものはどれですか。
public class Main {
    public static void main(String[] args) {
        int i = 0;
        do {
            if (i == 0) {
                i = 10;
                continue;
            }
            System.out.print("X");
        } while (i < 5);
        System.out.print(i);
    }
}

正解は「1⁠0」です。do 文では、本体の中で continue が実行されると、本体の残りを飛ばして条件式の評価に進みます。本体の先頭に戻るのではありません。1 回目は i が 0 なので i を 1⁠0 にして continue します。次に while (i < 5) が評価され、1⁠0 < 5 は false なのでループを終えます。X は一度も出力されず、最後に i の 1⁠0 を出力して「1⁠0」です。「X1⁠0」は continue で本体の先頭に戻ってもう一度実行すると考えた結果です。「無限ループになる」は continue で条件式を通らずに繰り返すと考えた答えです。do の本体で continue を使うことは文法上の問題が無いので「コンパイルエラーになる」も誤りです。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠4.html#jls-⁠1⁠4.1⁠3.1

問9for 文の書き方として、コンパイルできるものはどれですか。

正解は「for (int i = 0, j = 5; i < j; i++, j--) {}」です。for の初期化部には、式をカンマで並べるか、変数の宣言を 1 つ書けます。宣言は 1 つなので型は 1 回だけ書き、int i = 0, j = 5 のように同じ型の変数をカンマで並べます。更新部は式をカンマで区切って並べ、左から順に実行されます。i++, j-- は正しい書き方です。int i = 0, long j = 5 は 1 つの宣言の中で違う型を混ぜているので書けません。int i = 0, int j = 5 は型を 2 回書いているので、型が同じでもコンパイルエラーです。i++; j-- は更新部の区切りにセミコロンを使っていて、for の丸括弧の中のセミコロンは 2 つまでなのでコンパイルエラーです。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠4.html#jls-⁠1⁠4.1⁠4.1

問10次のコードをコンパイルしたときの結果として正しいものはどれですか。
public class Main {
    public static void main(String[] args) {
        int n = 0;
        block: {
            n++;
            if (n > 0) break block;       // (A)
            n = 10;
        }
        for (int i = 0; i < 3; i++) {
            if (i == 1) continue;         // (B)
            n += i;
        }
        check: {
            if (n > 2) continue check;    // (C)
        }
        System.out.print(n);
    }
}

正解は「(C) の行でコンパイルエラーになる」です。ラベルは繰り返しの文だけでなく、波括弧のブロックなど普通の文にも付けられます。ラベル付きの break の行き先はラベルの付いた文なら何でもよく、(A) の break block はブロックを抜けて次の for に進むので問題ありません。一方、continue は「今の繰り返しを終えて次の繰り返しに進む」ための文なので、行き先は while、do、for のどれかでなければなりません。(C) の check はブロックに付いたラベルなので、continue check は「check はループのラベルではない」というエラーになります。(B) はラベルの無い continue で、囲む for の次の繰り返しに進むので問題ありません。「3 と出力される」は (C) も break と同じように書けると考えた答えです。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠4.html#jls-⁠1⁠4.1⁠6

問11次のコードをコンパイルして実行したときの結果として正しいものはどれですか。
public class Main {
    public static void main(String[] args) {
        int n = 3;
        while (n-- > 0) {
            System.out.print(n);
        }
        System.out.print("/" + n);
    }
}

正解は「2⁠1⁠0/-1」です。while 文は、本体を実行する前に毎回条件式を評価し、false になった時点で終わります。最後に false になる回も条件式は評価されるので、条件式の中の副作用はその回にも起きます。n-- は今の値で比べてから n を 1 減らします。1 回目は 3 > 0 が true で n は 2 になり 2 を出力、続けて 1、0 を出力します。4 回目の評価は 0 > 0 で false ですが、このときも n-- が実行され n は -1 になります。そのあと /-1 を出力して「2⁠1⁠0/-1」です。「2⁠1⁠0/0」は false になる回には減らないと考えた結果です。「3⁠2⁠1/0」は比べる前に減らした値を出力すると考えた結果、「3⁠2⁠1⁠0/-1」は 0 > 0 でも本体を実行すると考えた結果です。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠4.html#jls-⁠1⁠4.1⁠2

問12次のコードをコンパイルして実行したときの結果として正しいものはどれですか。
public class Main {
    public static void main(String[] args) {
        int i = 0;
        loop:
        while (true) {
            switch (i++) {
                case 0:
                    System.out.print("A");
                    break;
                case 1:
                    System.out.print("B");
                    continue loop;
                default:
                    System.out.print("C");
                    break loop;
            }
            System.out.print("-");
        }
        System.out.print(i);
    }
}

正解は「A-⁠BC3」です。ラベルの無い break は、それを囲む最も内側の switch、while、do、for を抜けます。switch の中の break は while ではなく switch だけを抜けます。1 回目は switch (i++) が 0 を調べて i は 1 になり、A を出力して switch だけを抜け、続きの - を出力します。2 回目は 1 を調べて i は 2 になり、B を出力して continue loop で while の次の繰り返しに進むので、- は出力されません。3 回目は 2 で default に進み、i は 3 になり、C を出力して break loop で while ごと抜けます。最後に 3 を出力し「A-⁠BC3」です。「A1」は switch の break で while を抜けると考えた結果です。「A-⁠B-⁠C3」と「A-⁠B-⁠C-⁠3」は continue loop や break loop のあとも - を出力すると考えた結果です。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠4.html#jls-⁠1⁠4.1⁠5

問13次のコードをコンパイルしたときの結果として正しいものはどれですか。
public class Main {
    public static void main(String[] args) {
        int n = 0;
        while (true) {
            if (++n > 2) break;
        }
        System.out.print(n);        // (A)
        do {
            n++;
        } while (false);
        System.out.print(n);        // (B)
        while (true) {
            n++;
        }
        System.out.print(n);        // (C)
    }
}

正解は「(C) の行でコンパイルエラーになる」です。到達できない文はコンパイルエラーです。条件が定数の true の while は、中に自分を抜ける break が無ければ正常に終わらないとみなされ、そのあとの文には到達できません。1 つ目の while (true) には break があるので (A) には到達でき、問題ありません。do 文は条件が false でも本体を 1 回実行して正常に終わるので、(B) にも到達できます。最後の while (true) には break が無いので、その次の (C) は到達できない文となり「unreachable statement」のエラーになります。なお while (false) と書くと、逆に本体の文が到達できない文としてエラーになります。「3⁠4 と出力されたあと止まらない」は、到達できるかどうかをコンパイル時に調べることを見落としています。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠4.html#jls-⁠1⁠4.2⁠2

問14for (;;) のように for 文の条件式を省略したときの動きとして正しいものはどれですか。

正解は「条件式は true とみなされ、break などで抜けるまで繰り返す」です。for の初期化部、条件式、更新部はどれも省略できます。条件式が無いときは、条件が true のときと同じように本体を実行し、次の繰り返しに進みます。そのため for (;;) は break や return、例外などで抜けない限り終わらない無限ループです。while (true) と同じく、抜ける break が無ければ for のあとの文は到達できないとしてコンパイルエラーになります。「コンパイルエラーになる」は省略できないと考えた答えです。「false とみなされ」は空の条件を偽と考えた答え、「1 回だけ実行して」は do 文と混同した答えです。 出典 https://docs.oracle.com/javase/specs/jls/se1⁠7/html/jls-⁠1⁠4.html#jls-⁠1⁠4.1⁠4.1.2

ほかの分野

Java Silverの頁に、6分野の入口と試験の案内があります。

続きはゆめさくで

試験の知識を仕事につなげる一歩を、ここにまとめています。