OracleLevel 3

難易度は Level 1(やさしめ)〜Level 5(難関) の5段階です。

Java Silver SE 17 (1Z0-825-JPN)のサンプル問題(本番形式・解説付き)

Java Silver SE 17 (1Z0-825-JPN)(Oracle・Java SE 17 Programmer I(Java Silver SE17))の出題形式を、実際の問題で確かめられます。ここに掲載する5問は、無料の会員登録で解ける模試 第1回(60問)の冒頭から抜粋したオリジナル問題です。当サイトは全480問を本番CBT準拠の形式で収録しており、この5問はそのごく一部にあたります。

設問1

次のコード

 1: class Shape {
 2:     Shape scaled() {
 3:         return new Shape();
 4:     }
 5:     String name() {
 6:         return "shape";
 7:     }
 8: }
 9: class Circle extends Shape {
10:     Circle scaled() {
11:         return new Circle();
12:     }
13:     String name() {
14:         return "circle";
15:     }
16: }
17: public class Main {
18:     public static void main(String[] args) {
19:         Shape s = new Circle();
20:         System.out.println(s.scaled().name());
21:     }
22: }

このプログラムをコンパイルして実行しようとした場合の結果として、正しいものはどれか。

  • circle と表示される(正解)
  • shape と表示される
  • 行10 でコンパイルエラーになる
  • 行20 でコンパイルエラーになる

解説

行2 の戻り値は Shape、行10 は Circle で、Circle は Shape のサブタイプなので共変戻り値としてオーバーライドが成立する。行20 では s の静的型が Shape なので s.scaled() の型も Shape として扱われるが、実行時に返るのは Circle であり、続く name() も実体側の行14 が動く。参照型のサブタイプ関係にだけ認められる緩和で、int を long に替えるようなプリミティブの拡大変換とは別物である。「行10 でコンパイルエラーになる」は誤り。戻り値は同じ型かそのサブタイプであればよく、Circle は Shape のサブタイプにあたる。「行20 でコンパイルエラーになる」は誤り。行20 の s.scaled() の型は静的型どおり Shape で、Shape には name() の宣言があるので呼び出せる。

他の選択肢が誤りである理由

  • 「shape と表示される」行20 の scaled() も name() も実体側で解決されるため、行6 の値が表示されることはない。
  • 「行10 でコンパイルエラーになる」戻り値は同じ型かそのサブタイプであればよく、Circle は Shape のサブタイプにあたる。
  • 「行20 でコンパイルエラーになる」行20 の s.scaled() の型は静的型どおり Shape で、Shape には name() の宣言があるので呼び出せる。

設問2

次のコード

 1: public class Meter {
 2:     public static void main(String[] args) {
 3:         int[] values = {4, 8, 15};
 4:         int sum = 0;
 5:         for (int i = 1; i <= values.length; i++) {
 6:             sum += values[i];
 7:         }
 8:         System.out.println(sum);
 9:     }
10: }

このプログラムをコンパイルして実行した結果はどれか。

  • ループが3回まわり、全要素の合計の 27 が出力される
  • 行6 で ArrayIndexOutOfBoundsException がスローされる(正解)
  • values[1] と values[2] だけが足され、23 が出力される
  • 行5 の条件式 i <= values.length でコンパイルエラーになる

解説

行3 の配列は要素数3で、使える添字は 0 から 2 まで。行5 の条件が i <= values.length なので i は 3 まで進み、行6 の values[3] で ArrayIndexOutOfBoundsException がスローされる。添字は 0 始まりで上限は length - 1、という対応から、繰返しの条件は i < values.length と書くのが定石。行8 には到達しないので何も出力されない。

他の選択肢が誤りである理由

  • 「ループが3回まわり、全要素の合計の 27 が出力される」添字を 0 から始めて全要素を足した場合の値で、行5 は i を 1 から始めている。
  • 「values[1] と values[2] だけが足され、23 が出力される」行5 の条件を i < values.length と読んだ場合の値で、実際は i が 3 のときも本体に入る。
  • 「行5 の条件式 i <= values.length でコンパイルエラーになる」行5 の条件式も更新式も型として正しく、添字が範囲を超えるかどうかはコンパイル時には判定されない。

設問3

次のコード

 1: // p1/Gauge.java
 2: package p1;
 3: public class Gauge {
 4:     int raw() { return 7; }
 5:     public int scaled() { return raw() * 10; }
 6: }
 7:
 8: // p2/Panel.java
 9: package p2;
10: import p1.Gauge;
11: public class Panel extends Gauge {
12:     int show() { return raw() + scaled(); }
13:     public static void main(String[] args) {
14:         System.out.println(new Panel().show());
15:     }
16: }

2つのファイルをコンパイルすると、どうなるか。

  • 行12 の raw() を Panel から呼び出せないため、コンパイルエラーになる。(正解)
  • Panel が継承した raw() と scaled() を呼べて、77 と表示される。
  • scaled() の結果が数えられず、raw() の 7 だけが表示される。
  • 見えない raw() を飛ばして scaled() だけを足し、70 と表示される。

解説

行4 の raw() には修飾子が無く package-private なので、可視範囲は p1 の中だけである。Panel は Gauge のサブクラスだが p2 にあるため raw() を継承せず、行12 の呼び出しは「シンボルを見つけられません」になる。行5 の scaled() は public なので Panel へ継承され、その本体にある raw() 呼び出しは Gauge の中(=p1)に書かれているので問題ない。同じ場所を protected にしていれば別パッケージのサブクラスへ届く ── package-private と protected の差が出るのがまさにこの象限である。「Panel が継承した raw() と scaled() を呼べて、77 と表示される」は誤り。行4 が protected か public であればこの値になるが、修飾子が無いため p2 からは見えない。「scaled() の結果が数えられず、raw() の 7 だけが表示される」は誤り。行12 の raw() だけを数えた値だが、その raw() 自体が Panel からは呼び出せない。「見えない raw() を飛ばして scaled() だけを足し、70 と表示される」は誤り。行12 のうち scaled() だけを数えた値であり、raw() の記述がコンパイル時に残っている。

他の選択肢が誤りである理由

  • 「Panel が継承した raw() と scaled() を呼べて、77 と表示される。」行4 が protected か public であればこの値になるが、修飾子が無いため p2 からは見えない。
  • 「scaled() の結果が数えられず、raw() の 7 だけが表示される。」行12 の raw() だけを数えた値だが、その raw() 自体が Panel からは呼び出せない。
  • 「見えない raw() を飛ばして scaled() だけを足し、70 と表示される。」行12 のうち scaled() だけを数えた値であり、raw() の記述がコンパイル時に残っている。

設問4

次のコード

 1: public class Grader {
 2:     public static void main(String[] args) {
 3:         char grade = 'A';
 4:         System.out.println(grade);
 5:         System.out.println(grade + 1);
 6:     }
 7: }

このプログラムを実行したときの出力はどれか。

  • A と B が順に出力される
  • A と A1 が順に出力される
  • A と 66 が順に出力される(正解)
  • 65 と 66 が順に出力される

解説

行4 は char をそのまま渡しているので println(char) が選ばれ、文字として A が出力される。行5 は char と int の加算で結果が int になるため println(int) が選ばれ、'A' のコード値 65 に 1 を足した 66 が数値として出力される。同じ変数でも、渡す式の型が変わるとどのオーバーロードが選ばれるかが変わる点が要で、文字列連結との違いもここで分かれる。

他の選択肢が誤りである理由

  • 「A と B が順に出力される」行5 は char どうしの加算ではなく char と int の加算なので、結果は int になり文字としては出力されない。
  • 「A と A1 が順に出力される」行5 の + は数値の加算で、片方が文字列のときだけ連結として働く。
  • 「65 と 66 が順に出力される」行4 は char を受け取る println が選ばれるため、コード値ではなく文字が出力される。

設問5

次のコード

 1: public class Router {
 2:     static String pick(int n) {
 3:         String r = "";
 4:         switch (n) {
 5:             case 1:
 6:             case 2:
 7:                 r += "A";
 8:             case 3:
 9:                 r += "B";
10:                 break;
11:             default:
12:                 r += "C";
13:         }
14:         return r;
15:     }
16:     public static void main(String[] args) {
17:         System.out.println(pick(2));
18:         System.out.println(pick(3));
19:         System.out.println(pick(9));
20:     }
21: }

このプログラムを実行したときに成り立つ記述はどれか。(2つ選択)

  • 行7 の後に break が無いため、n が 2 のときは行9 も実行され、pick(2) は AB を返す(正解)
  • 行5・行6 のように本体を持たない case ラベルを続けて書くと、switch 文の構造としてコンパイルエラーになる
  • 行5 と行6 はどちらも行7 へ流れ込むので、n が 1 でも 2 でも同じ結果になる(正解)
  • 行18 の呼び出しでは行10 の break を通らずに行12 まで進むため、BC が出力される
  • 行4 の switch の対象を long 型に変えても、整数どうしなので同じように動作する

解説

switch 文は一致した case ラベルから下へ流れ、break に当たるまで止まらない(fall-through)。n が 2 なら行7 で A を足し、break が無いのでそのまま行9 で B を足して AB になる。n が 3 なら行9 だけで B を足し、行10 の break で switch を抜けるので default には進まない。n が 9 は default で C。本体を持たない case ラベルを続けて並べるのは、複数の値を同じ処理へ流し込む正しい書き方である。この落ち方こそ、矢印形式で fall-through しない switch 式との最大の違いである。出力は AB/B/C。

他の選択肢が誤りである理由

  • 「行5・行6 のように本体を持たない case ラベルを続けて書くと、switch 文の構造としてコンパイルエラーになる」同じ処理へ流し込むために、本体を持たない case ラベルを続けて並べるのは正しい書き方である。
  • 「行18 の呼び出しでは行10 の break を通らずに行12 まで進むため、BC が出力される」n が 3 のときは行8 の case に入り、行9 で B を足したあと行10 の break で switch を抜ける。default へは進まない。
  • 「行4 の switch の対象を long 型に変えても、整数どうしなので同じように動作する」switch 文の対象にできるのは char・byte・short・int とそのラッパー、String、enum である。long・float・double・boolean は使えない。

続きは、会員登録なしでそのまま50問解けます。採点と解説つきで、上と同じ本物の問題です。

登録なしで50問解く